In this article we are going to learn about Strategy Design Pattern.
- What is Strategy design pattern?
- What are the basic principles?
- How to implement?
- where we can use this?
I have used Java with Eclipse and C# with VS2010.
What is Strategy design pattern?
In OO design, when we get a set of objects sharing some behaviors and some changing behaviors and we want to have a common way to implement those changing behaviors.
In that scenario we can apply strategy design pattern. Strategy design pattern allows us to cal by reference(interface) which decoupled dependent functions. In that way we can encapsulate specific behavior/algorithm from common behaviors.
Strategy pattern use composition through interface to select changeable behavior in dynamically. That means , the client will use an object that contains composition of strategy(changeable behavior family) and there will behavior specified class implement changed behaviors.
We untie changing behaviors from super class to sub class that helps us changing behaviors without any side effects.
Let say, algorithm implementation can be selected dynamically by interface using strategy pattern. The interface will contain common to all supported algorithms. The implemented interface classes will define those algorithm.
Let’s consider the animal planet where every one is an animal. Let assume this three Dog, Cat, Cow. All of the animal have common behavior is barking. But, all are different. So, if we want to apply Strategy, we need to isolate the barking behavior. And have an access way from animal super class. And, particular dog/cat/cow will implement their own barking. So, we have implemented strategy.
Principles :
- Define Changing behaviors/algorithm/logic family
- Encapsulate each one and make them interchangeable(by inheriting them from single interface)
- Client should be able to use it independently.
UML:
How to implement?
Firs, let’s think about how to implement strategy. Following basic principle, we have to define behaviors.
And define those behaviors commonly accessible through interface
And the super class, who’s subclasses have common behaviors, will use this interface to get behavior.
In here, the super class and the strategy interface will have “Has A” relation. That means the super class will have a member who is the interface type.
I prefer to use the strategy Interface for accessing it data(changeable).
The context class(super class) will have common way to access changeable behaviors but the extended classes will define change behaviors/algorithm in itself. (in example, I did it in the constructor).
It will call those change behavior implement classes(concrete of interfaces)
We can keep the super class as abstract if we do not need the super class as context. (In example, I have kept as normal)
Example :
Let’s consider a ship building example. Assume, we need to build 4 type of ship which has every thing common except how it works. Let say
- Battle Ship : Work for carrying heavy artillery.
- Cargo Ship : Work for carrying Goods
- Passenger Ship : Work for carrying people
- Fire Ship : Work for carrying heavy artillery.
As they have a lot of property common, we need a super class containing common code that reduce code duplication.
And, here we have same behavior working (method) but differ from each other. So, if we add a common method Work in the super class , then we have to override for each sub class as it differs.
Rather than doing that, lets apply the strategy pattern. Strategy suggest to apply Has A Relationship rather Is A relation. (and we know is a refers to sub class and has a refers to composition , like element of class) .
Then we have to apply this work behavior(which is the changing one) as strategy and include the strategy implemented class as member of abstract ship object through strategy.
So , lets isolate working behavior carry() in separate Interface.
public interface IStrategyBehaviour {
public void carry();
}
And, Now we need this behavior separately implemented behaviors.
- Battle ship and fire ship will have commonly containing heavy artillery.
- Cargo ship will carry goods and passenger ship will carry people.
So, we will need mainly 3 class(type of changed behaviors) implementing separate behaviors.
And this way we can establish a way to access those changed behaviors.
public class HeavyArtillery implements IStrategyBehaviour{
public void carry() {
System.out.println("carrying heavy artillery");
}
}
public class Goods implements IStrategyBehaviour{
public void carry() {
System.out.println("carrying Goods");
}
}
public class People implements IStrategyBehaviour{
public void carry() {
System.out.println("carrying People");
}
}
So, if we call by IStrategyBehaviour from context(ship class) then it will be generic(decoupled). Okay, now lets define the context .
In here, we have 4 type of ships. They have common properties. So, we will create a class called Ship(you may declare as abstract, in example I have kept as normal)
public class Ship {
private String name;
public IStrategyBehaviour work;
public void getToWork(){
work.carry();
}
public void setToWork(IStrategyBehaviour aWork){
work=aWork;
}
public Ship(String aName){
name=aName;
}
public String getName() {
return name;
}
}
And, we need this extend particular ship. And, don’t forget we need to assign ship specified carry behavior.
To do that we will assign work as new behavior class in the contractor. That means cargo ship will be
public class CargoShip extends Ship{
public CargoShip(String aName) {
super(aName);
System.out.println("A cargo ship is created");
work=new Goods();// cargo is assigning work as goods, that means it carry goods.
}
}
Like the same , we will do for fire ship, battle ship, passenger ship.
public class FireShip extends Ship{
public FireShip(String aName) {
super(aName);
System.out.println("A fire ship is created");
work=new HeavyArtillery();
}
}
public class BattleShip extends Ship{
public BattleShip(String aName) {
super(aName);
System.out.println("A Battle ship is created");
work=new HeavyArtillery();
}
}
public class PassengerShip extends Ship {
public PassengerShip(String aName) {
super(aName);
System.out.println("A passenger ship is created");
work=new People();
}
}
So, this context classes have implemented changed behavior by assigning changed object. Now, we need a client .
In the example , I have changed the a ship’s default behavior from client to prove that we can change the behavior/algorithm by interface.
public class Program {
public static void main(String[] args) {
Ship aFireShip = new FireShip("Fire Ship");
System.out.print("Fire ship is " );
aFireShip.getToWork();
aFireShip.setToWork(new Goods());
System.out.print("Fire ship is now ");
aFireShip.getToWork();
}
}
So, finally we have changed the grouped behavior by interface.
Java Example :
- We can use strategy in many way, but I use simply to understand strategy specifically.
- I have added more of command line output to get more understanding of the steps.
C# Example :
- I have to change some method names and implementations as they work differently in dot net.