First of all. What is the Strategy Pattern?
“The Strategy Pattern defines a family of algorithms, and makes them interchangeable”
This pattern allow us to apply an important concept of object oriented programming: favor composition over inheritance, which we can translate as the ability to change an object’s behavior on runtime.
With this small introduction about the Strategy Design Pattern, let’s see some code.
Let’s suppose (with a lot of imagination) that we are working on a search engine. This search engine works over a data source, searching for a particular value.
The most common search algorithms, we could say, are the linear search and the binary search. The last one has the particularity of being (in average) a lot faster than the first one, with the trade-off of having a prerequisite: the data source must be sorted.
So, talking in the Strategy Pattern terminology, we have a family of algorithms (search algorithms) and we want to interchange them in our search engine.
As we can see, the search engine, after sorting the data source, interchanges its search strategy to the binary search, because it is the best search algorithm for a sorted list.
For all this, we just have three classes and one interface. Pretty well, right?
The same result can be achieved by using an Enum based implementation.
The behavior is the same, but instead of using an interface and multiple implementations, we just use one Enum.
Pros of the Enum implementations
In first place, the number of classes is reduced without generating an absurd coupling, on the contrary, all the code in the Enum is cohesive and responds to the same necessity: to make a search.
The responsibility of the search is well defined in the Enum itself.
In second place, the Enums are singletons, meaning that it exists one and only one instance of each implementation.
“Hey, what did just happen? 2 patters on 1?” Yes, I know that many developers considerate the Singleton as an “Anti-pattern”, and that should be another discussion, but this matter save us from the complexity of having to instance objects and use other patterns such as Builder and Factory patterns.
The Enum are singletons: We are not required to instance them, or implement factories or builders.
In third place, our Strategy gains the capacity of persistence. Relational databases usually support enumerated values, and using a good ORM (Object-Relational Mapping) framework we can easily persist our SearchEngine and its state (e.g. its data source and its strategy).
Taking this same idea to others domains, such as users with roles and profiles, or vehicles with different equipment, will give us control over the algorithms used on runtime not just from the code, but also from the database.
We can think about it as a kind of algorithm persistence.
If we would have to persist the SearchEngine in the previous implementation (without Enum) using an ORM framework, possibly we would need a serializable field that determines which Strategy is set, and then use that field at the time of fetching the database result to know, after some comparings and object creations, which Strategy we should set to our instance on runtime.
With the Enum based implementation, this serializable field is the Enum itself, and the comparings and object creations are not longer required.
Cons of the Enum Implementation
All that glitters is not gold, and there are also cons.
To start with, as I mentioned before, the Enums are singletons, meaning that unique instances are shared above the entire application. This implies that the Enums should be stateless, at least in almost all the applications that are going to support some kind of concurrency.
Even though is not very common for a Strategy to have a state, if our implementation requires one, the Enums are not the right path to follow.
Our Strategy Pattern implementation must be stateless.
Also we must keep in mind the number of implementations of the Strategy that we need. Having two, three, or four different algorithms of the same family is not the same that having ten (or more). In such case, we will have to decide if we want to have an Enum with hundreds (or thousands) of lines of code, or if we prefer to split the code in several classes implementing an interface.
At last, but not less important, the Enums do not support class inheritance (although they do support Interfaces implementation). If we want to have some subclasses of a BinarySearchStrategy, such as a RecursiveBinarySearchStrategy and a IterativeBinarySearchStrategy classes, we will need something more complex than just an Enum.
The main idea was to show an alternative to the classic way of thinking about the Strategy Pattern (multiple classes implementing an interface) that reduces the boilerplate code (that code that we hate to write, but we must do) and gives us a different way to see the Enum, not as just enumerated values, but as enumerated algorithms.
Also, the idea was to share the concept of algorithms persistence in a simple and clean way.
To use or not to use an Enum based implementation is a choice that each developer will have to take, following his/her own criteria and the trade-off that it represents, but maybe with this little reading, he or she could get and extra tool.