The Strategy design pattern is often regarded as a substitute for first-class functions in languages that lack them.
So for example say you wanted to pass functionality into an object. In Java you’d have to pass in the object another object which encapsulates the desired behavior. In a language such as Ruby, you’d just pass the functionality itself in the form of an anonymous function.
However I was thinking about it and decided that maybe Strategy offers more than a plain anonymous function does.
This is because an object can hold state that exists independently of the period when it’s method runs. However an anonymous function by itself can only hold state that ceases to exist the moment the function finishes execution.
In an object-oriented language that supports first-class functions, does the strategy pattern have any advantage over using functions?
3
When the language supports references to function (Java does since version 8), these are often a good alternative for strategies, because they usually express the same thing with less syntax. However, there are some cases where a real object can be useful.
A Strategy interface can have multiple methods. Let’s take an interface RouteFindingStragegy
as example, which encapsulates different route finding algorithms. It could declare methods like
Route findShortestRoute(Node start, Node destination)
boolean doesRouteExist(Node start, Node destination)
Route[] findAllPossibleRoutes(Node start, Node destination)
Route findShortestRouteToClosestDestination(Node start, Node[] destinations)
Route findTravelingSalesmanRoute(Node[] stations)
which then would all be implemented by the strategy. Some route-finding algorithms might allow internal optimizations for some of these use-cases and some might not, so the implementor can decide how to implement each of these methods.
Another case is when the strategy has an inner state. Sure, in some languages closures can have inner state, but when this inner state gets very complex, it often becomes more elegant to promote the closure to a full-fledged class.
3
It is not true that an anonymous function can only hold state that ceases to exist when the function finishes execution.
Take the following example in Common Lisp:
(defun number-strings (ss)
(let ((counter 0))
(mapcar #'(lambda (s) (format nil "~a: ~a" (incf counter) s)) ss)))
This function takes a list of strings and prepends a counter to each element of the list. So, for example, invoking
(number-strings '("a" "b" "c"))
gives
("1: a" "2: b" "3: c")
The function number-strings
internally uses an anonymous function with a variable counter
that holds state (the current value of the counter) which is reused every time the function is invoked.
In general, you can think of a closure as an object with only one method. Alternatively, an object is a collection of closures that share the same closed-over variables. So I am not sure whether there are cases in which you need to use an object instead of a closure: I would argue that both are ways of looking at the same pattern from different perspectives.
In particular, the strategy pattern requires an object with only one method, so a closure should do the job. But, as Philipp has observed in his answer, depending on the circumstances (complex state) and programming languages you may get a more elegant solution by using objects.
2
Just because two designs can solve the same problem doesn’t mean they are direct substitutions for each other.
If you need to track state in a functional program, you don’t mutate a closed over variable, even if the language allows it. You arrange to call a function that takes in one state as an argument and returns the new state as its return value.
Your architecture will look very different, but you’ll accomplish the same goal. Don’t try to force one paradigm’s patterns directly onto the other one.
3
Strategy is a concept, a useful recipe for solving a particular, recurring problem. It’s not a language construct, nor is it about any one form of implementation. A closure can be used to implement Strategy one day and Observer the next day.
The term Strategy is mostly useful in conversations with other programmers to concisely express your intent. There’s nothing magical about it.
3