Tuesday, June 23, 2009

Erlang for Java programmer - Design patterns, p.1

The Gamma et al. "Design patterns" book formulates common desing patterns that could be applied to any object-oriented language. When we move to functional language domain though, many OO design patterns simply don't apply. This is hardly surprising, because functional programmers by definition don't do OO design. Some of the problems that OO design patterns are supposed to solve still have their counterparts in functional programming.

We are going to walk through the book's pattern catalog and try to show a matching Erlang approach for the OO patterns, where possible.

Going forward, I will be referring to "Design patterns" book as DP. In (unlikely) case you'll want to follow, it'll be helpful to have this book handy.




Adapter (Wrapper)



Intention(DP): Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.



Let's just substitute "class" to "function", and we'll have it for Erlang:



Convert the interface of a function into another interface clients expect. Adapter lets functions work together that couldn't otherwise because of incompatible interfaces.



Now, function's interface obviously being its arguments, in most cases we can easily create adapter for that function, which is another function having desired set of arguments.



Example:



Trying to stick closely to DP example, let's assume that we are working on drawing editor and want to implement text drawing capabilities in module textshape. The behavior that we have decided to use for all shape kinds contains bounding_box/1 function that returns bottom left and top right coordinates for any shape. So we are now concerned with task of writing bounding_box() flavour for text shapes. We have 3rd party module textview at our disposal, and we want to reuse it for our purpose. It happens that textview exports (in Java terms, has public) functions:



get_origin(TextView) that returns origin point of the text view in form of tuple {X, Y}, and

get_extent(TextView) that returns width and height of the text view in form of tuple {Width, Height}.



Our bounding_box/1 function then might look as follows:




# Calculates bounding box for text drawing;
# returns tuple {TopLeftX, TopLeftY, BottomRightX, BottomRightY}




bounding_box(TextShape) ->
TextView = convert_to_textview(TextShape),
{X, Y} = textview:get_origin(TextView),
{Width, Height} = textview:get_extent(TextView),
{X, Y, X + Width, Y + Height).









What about convert_to_textview/1 function? Not to worry, it should be easy. Remember, TextView and TextShape are not objects, but rather data structures, so conversion is normally just a matter of knowing what these structures are and matching parts of them. Below is a sample implementation, just to give an idea:




# In this case, we assume that TextShape is a list of properties, such as:
# [{text, "Desing patterns"}, {font, "Arial"}, {color, "red"}, .....];
# TextView is a dictionary with keys viewtext, viewfont, viewcolor, viewstyle etc.




convert_to_textview(TextShape) ->
lists:foldl(fun(Prop, Acc) ->
{Key, Value} = convert_prop(Prop),
case Key of
not_present ->
Acc;
_Other ->
dict:store(Key, Value, Acc)
end
end, dict:new(), TextShape).


convert_prop({"text", Value}) ->
{"viewtext", Value};
convert_prop({"font", Value}) ->
{"viewfont", Value};
%% Conversions for other properties
...................................
%% Properties that don't have counterparts in TextView structure
convert_prop({_, _}) -> not_present.










That's it, we have Adapter implementation blueprint for Erlang. Looks kinda trivial, don't you think? That's what you're gonna like once you start Erlang coding - many things are easier and definitely less verbose compared to Java.

No comments:

Post a Comment