Strategy Design Pattern
Abstract
Strategy Design Pattern is a behavioral design pattern. It works by abstracting out that part of a class code that is prone to changes into a strategy, which can dynamically be injected at runtime
When will we need a Strategy design pattern?
To understand the strategy pattern in a lucid manner, let us take an example of a Martial Arts game you wish to develop. This game allows players to select a fighter of different martial arts styles. Let us assume Judo, Karate, KungFu are some of them
All these forms implement a common superclass called MartialArt
Some of the basic functions we expect a fighter to make are kick(), punch() and grab(). Let us assume the basic functionalities to do so are defined in the superclass
Now the requirement is that Judo fighters do not kick or punch, but only grab. This is how we will implement the same:
Here arises the first problem with this design: Problem 1: Whenever any type of martial art does not wish to implement some basic method, they have to override it to do nothing
Now let us say the Karate and KungFu fighters have a special type of kick called flying kick. Both the classes now need to override the kick method to do a flying kick
Here arises the second problem with this design: Problem 2: Multiple classes need to be touched to edit the common functionality among them, and we move away from the benefits of inheritance and introduce duplication in the code
Here is where a basic principle of OO design comes into play: Abstract out the part of your code that is susceptible to changes from the part which remains constant
How does the Strategy Design Pattern work?
In our fighting game example, the kick function is something that can change for different fighting styles. We can also anticipate that punch and grab might have different behaviours based on the fighting style
We can create two concrete classes for each type of kicking strategy
Now that we have extracted the KickStrategy out of our fighter classes, we can use composition to inject the strategy into fighter classes
We can make our code even easier to modify, by programming to the interface rather than the implementation. If tomorrow KungFu fighters want to kick in a different style, we can do so at runtime using polymorphism rather than edit the classes every time
Thus if later we decide that a KungFy fighter needs a new type of kick called rotating kick, we just need to pass that strategy to its constructor;
If any fighter does not wish to kick, we can simply implement the KickStrategy to do nothing
This pattern of abstracting out the strategy of doing a method from the entity classes, and setting it polymorphically at runtime, is the Strategy Design Pattern
We can now summarize the above design changes in a class diagram
Note that we can make the superclass MartialArt abstract, and specify the default implementation for kick(), punch(), grab() in the abstract class. Fighters that wish to stick to the default implementation can just re-use the code
Pros and Cons of Strategy Design pattern
Pros:
- We can avoid using conditionals like switch if-else statements to decide the behaviour of entity classes at run time
- The main behavioural algorithms are abstracted out from the main context entities These advantages make our code easy to maintain and extensible
Cons:
- Since we have abstracted out the behaviour of context entities from their classes, the onus is on the client to understand various strategies to implement the behaviours, and pass it accordingly
- We will end up creating more objects in our application, demanding more memory footprint
Difference between Strategy and Factory Design Pattern
Strategy | Factory |
---|---|
It is a behavioural design pattern | It is a creational design pattern |
It determines how objects will behave at runtime | It determines how the objects will be created at runtime |
Using strategy pattern we can determine how will a fighter kick/ punch/ grab | Using factory pattern we can determine how will a fighter be created in the first place |
FAQ
Q. How do I know I should use the Strategy Design Pattern?
A. Strategy pattern should be used when you have a use case of deciding how your objects will behave dynamically. In scenarios where you have a lot of classes with some of them having similar behaviour for few methods, and in the future you plan to change this behaviour frequently, Strategy pattern will help you achieve reusability and extensibility in your code.
Q. Why do we use composition?
A. As a thumb rule, hasA relationships are more flexible than isA relationships. Composition allows you to change the behaviour of your classes at runtime. You also end up encapsulating the set of algorithms that determine the behaviour of classes into the classes themselves