Strategy pattern is part of the behavioral design patterns. It defines a couple of plans/algorithms to achieve the desired results and then depending on the client request, appropriate algorithm is executed, at the run time. This is one of the easiest pattern to be learnt and implemented, as it is nothing but the basic functionality of the interfaces.
What is Strategy pattern ?
According to GoF’s definition, this pattern is :
Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
As per the above definition, we create a number of implementations for the same process, encapsulate them using a kind of wrapper class, which handles the client request and this wrapper invokes the appropriate strategy, at the run time.
A real world example :
A newly established organization is hiring new members for development teams. They have the requirements of Software engineers, Senior Software engineers and Team leads. Depending on their designations, they give them the pay scales, define policies for leaves, their responsibilities etc. So overall we can say that for each of the designations, they have their own strategies to manage them. So, technically speaking, this is the situation where we can easily go for the strategy pattern.
Let’s convert our example into technical code :
To implement this pattern our system code will be divided into the following components
1. IStrategy : An interface which will be implemented by our different strategies, based on their types. In our case it will be IEmployeeStrategy.
2. ConcreteStrategies : These will be implementing the strategy interface defined above and define their strategies for the employees . In our example, these will be the classes called SoftwareEngineer, SeniorSoftwareEngineer & TeamLeads.
3. ContextClass : This class will be handling the request from the client code and execute the appropriate strategy. In our example, it will be HiringStrategyContext.
4. Client : This is the client class which will be requesting for a strategy to be used for a newly hired employee.
So we will be defining our abstract strategy and based on the designations, they will be implemented. So our initial code setup for defining this strategy concept will be like the following :
Next, our client code or HR would simply hire the members and call the EmployeeStrategies() to give them the details of their policies, procedures, pay scale etc.. But this will be done indirectly, through the use of context class, which in our case is the HiringStrategyContext. This context class will receive the request at run-time, using the concept of containment, appropriate strategy will be defined. So our strategy context class will be like the following
Now run the code and see the results. So we have different strategies defined for different employees.
So this was about the strategy pattern.
Could we have used the Factory Pattern instead of the Context class : One question that may come here is that, could we have used the Factory method pattern here instead of using the context class. The reason for this question is that the context class is doing the job very much similar to a factory could have done, i.e. create an instance of the appropriate strategy and result in call to its implementation. But the reason we should not go for it is :
- The most basic reason is that Factory method design pattern is aimed at creating the instances of the classes, where as the strategy pattern is aimed at calling the appropriate concrete strategies based on the client requirements. This is nothing but the basic type of these patterns, which separates them as two different category patterns i.e. Creational or Behavioral pattern.
- In future, if we have to define the strategies for another designation, we will be required to the change the factory method implementation. This would have resulted in the violation of the Open/Closed design principle.
- Using factory, we could have created instances of different classes and may have called methods which might not have been serving the same purpose.
Like, here for ex, all our methods are serving the same purpose of defining the strategies/policies of a newly hired member. But in factory, we could have created the instance of ClassA for Save() purpose and instance of ClassB() for Delete() functionality, which are completely different.
So this was all about Strategy design pattern.