By : Saif Ikram
Published on : 16-October-2007
Introduction
As we all have a brief idea of what design patterns and what role it plays in the Software Development Life Cycle. Now we will look into one of the most important pattern known as "Strategy Pattern". Lets start up with an example.
In this Article we will also use the following design principles:
- Identify the aspects of your application that vary and separate them from what stays the same.
- Program to an interface, not an implementation
- Favor Composition over inheritance
A simulator which demonstrates the types of worldwide cars and their features. Users can choose any type of cars, then the simulator should give a demonstration of the type of car selected with the features available for that car.
Start with the basic design
Consider the following basic design:
Here Car is the base class. Taxi and RentedCar’s are the derived classes. Carry() is defined in base class and run() is overridden in the derived classes as required. Suddenly you recognise that, as this is for worldwide cars, there are some cars, which go for race.
Only change required is to add a race() method in the base class so some cars can go for the race.
Update the code with race() method and now the code is ready for demo.
User starts the Demo, Some thing went horribly wrong.
Now code needs to be modified. I.e.
Modify Taxi Class
- Race() to do nothing
Modify RaceCar Class
- Carry() to do nothing
Consider about ToyCar they do not race Nor they do not Carry
I.e.
- Create the ToyCar Class
- Race() to do nothing
- Carry() to do nothing
As long as new type of car’s come, the more modification is required. Let us think about some alternative solution like the following below.
In the above design, there is no reusability. As long as you add classes you need to override the methods carry() or race() etc. so this is not a good design.
Let us use Design Principle one:
Like this :
And one more thing we are using classes where in we do not have a chance for dynamic behaviour. Ie. for example Taxi started taking passengers and after some time it want to go for a race, which is not possible as per the last design.Ok. Lets implement the second design principle
Let see the design now using the two principles:
We just had designed for the behaviour of Car’s like Carry, Race etc.. Now we need to design the Types of Cars. It’s now time to use the third principle.
Here is the final design:
"Strategy Pattern" "Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it."
Now the code walk through:
Car Class
Public abstract class Car {
CarryBehaviour carryBehaviour;
RaceBehaviour raceBehaviour;
public Car(){
}
public abstract void run();
public void race(){
raceBehaviour.race();
}
public void carry(){
carryBehaviour.carry();
}
public void setraceBehaviour(RaceBehaviour rb){
raceBehaviour = rb;
}
public void setcarryBehaviour(CarryBehaviour cb){
carryBehaviour = cb;
}
}
RaceBehaviour (Interface), RaceCar (Class) & RaceNoWay (Class):
public interface RaceBehaviour{
public void race();
}
public class RaceCar implements RaceBehaviour{
public void race(){
system.out.println(“I am racing”);
}
}
public class RaceNoWay implements RaceBehaviour{
public void race(){
system.out.println(“I can’t race”);
}
}
CarBehaviour (Interface), CarryPeople (Class) , NonCarrier (Class) & CarryLoad (Class):
public interface CarryBehaviour{
public void carry();
}
public class CarryPeople implements CarryBehaviour{
public void carry(){
system.out.println(“I can carry only people”);
}
}
public class NonCarrier implements CarryBehaviour{
public void carry(){
system.out.println(“I can’t carry”);
}
}
public class CarryLoad implements CarryBehaviour{
public void carry(){
system.out.println(“I can carry only Load”);
}
}
Car Class
Public class Taxi extends Car {
public Taxi(){
carryBehaviour = new CarryPeople();
raceBehaviour = new RaceNoWay();
}
public void run(){
System.out.println(“Running a Taxi”);
}
}
Jeep Class
Public class Jeep extends Car {
public Taxi(){
carryBehaviour = new CarryLoad();
raceBehaviour = new RaceNoWay();
}
public void run(){
System.out.println(“Running a Jeep”);
}
}
RaceCar Class
Public class RaceCar extends Car {
public Taxi(){
carryBehaviour = new NonCarrier();
raceBehaviour = new RaceCar();
}
public void run(){
System.out.println(“Going for Race”);
}
}
ToyCar Class
Public class ToyCar extends Car {
public Taxi(){
carryBehaviour = new NonCarrier();
raceBehaviour = new RaceNoWay();
}
public void run(){
System.out.println(“Play with ToyCar ”);
}
}
RentalCar Class
Public class RentalCar extends Car {
public Taxi(){
carryBehaviour = new CarryPeople();
raceBehaviour = new RaceNoWay();
}
public void run(){
System.out.println(“I am Rented Car”);
}
}
Small Demo
Public class WorldCarSimulator {
public static void main(string[] args){
Car Ferrari = new RaceCar();
Ferrari.carry();
Ferrari.race();
Ferrari.run();
Car RoadRunnerTaxi = new Taxi();
RoadRunnerTaxi.carry();
RoadRunnerTaxi.race();
//Changing the behaviour dynamically
RoadRunnerTaxi.setraceBehaviour(new RaceBehaviour());
RoadRunnerTaxi.race();
}
}
Strategy Pattern Explained
Participants
The classes and/or objects participating in this pattern are:
- Strategy (SortStrategy) : declares an interface common to all supported algorithms. Context uses this interface to call the algorithm defined by a ConcreteStrategy
- ConcreteStrategy (QuickSort, ShellSort, MergeSort) : implements the algorithm using the Strategy interface
- Context (SortedList) : is configured with a ConcreteStrategy object
- maintains a reference to a Strategy object : may define an interface that lets Strategy access its data.
- Observer (IInvestor) :defines an updating interface for objects that should be notified of changes in a subject.
- ConcreteObserver (Investor) :maintains a reference to a ConcreteSubject object stores state that should stay consistent with the subject's implements the Observer updating interface to keep its state consistent with the subject's
1 comment:
You write very well.
Post a Comment