Saturday 10 May 2014

Strategy Design Pattern

behavior can be selected at run time.

Will see it by detailed Example

Lets try to implement a simple Car game, in that all cars can swim. But Each type of car has specific appearance mechanism as compared to others.

Lets do initial design

As per the given requirement All cars can swim, but the appearance mechanism is different. So we can create an abstract Car class, and implement the swim functionality (Which is common for all Cars) in it, and make appearance functionality as abstract, let the sub classes implements their own functionality.




public abstract class Car{

 public void swim(){
  /* Swim related code */
 }
 
 /* It is implemented by all subclasses */
 public abstract void appearance(); 
}

class FerrariABC extends Car{
 public void  appearance(){

 }
}

class McLarenABC extends Car{
 public void  appearance(){

 }
}


class JaguarABC extends Car{
 public void  appearance(){

 }
}



Now design seems to be absolutely perfect, Life is so happy, if there is no requirements change.

Now Your Manager asked you that, In the next version of the game we are going to provide some more cars like LamborghiniABC, PorscheABC, which can fly in addition to swim.





Now it is your turn to implement the functionality.

Idea 1
Let me implement fly functionality in the abstract Car class. I will override the fly functionality in the sub classes which can't fly.

Now the design seems to be like below.


public abstract class Car{

 public void swim(){
  /* Swim related code */
 }

 public void fly(){
  /* Fly Related Code */
 }
 
 /* It is implemented by all subclasses */
 public abstract void appearance(); 
}

class FerrariABC extends Car{
 public void  appearance(){

 }

 public void fly(){
  /* Empty Code */
 }
}

class McLarenABC extends Car{
 public void  appearance(){

 }

 public void fly(){
  /* Empty Code */
 }
}

class JaguarABC extends Car{
 public void  appearance(){

 }

 public void fly(){
  /* Empty Code */
 }
}


class LamborghiniABC extends Car{
 public void  appearance(){

 }

}


class PorscheABC extends Car{
 public void  appearance(){

 }
}

Problems With Idea 1
1. After some time, there may be chance that some more cars are added, which can't fly, then you must override the fly functionality.

2. There may be a chance that some cars which are not supporting fly functionality now, can support in near future as per new requirements. In that case you have to remove the existing overridden fly method code.

Idea 2
1. Why can't I make a FlyingCar interface and let the classes which want to fly implement the interface.

Problems
1. Then your fly functionality code is getting duplicated in all the classes which are implementing fly functionality.

Solution
The main idea of Strategy design pattern is,separately implement the functionality which will change. Here fly functionality is different for various cars. Provide an interface FlyingCar and make two classes CarCanFly and CarCannotFly implements the interface FlyingCar.


public interface FlyingCar {
 public void fly();
}

public class CarCanFly implements FlyingCar {
 public void fly(){
  /* Fly functionality code goes here */
  System.out.println("I Can Fly");
 } 
}


public class CarCannotFly implements FlyingCar {
 public void fly(){
  /* Empty code*/
  System.out.println("I Can't Fly");
 } 
}

Update the Car class like below


public abstract class Car{
   FlyingCar flyCar;

  public void swim(){
   /* Swim related code */
  }

  public void fly(){
   flyCar.fly();
  }

  public void setFlyBehavior(FlyingCar flyCar){
   this.flyCar =  flyCar;
  }

  /* It is implemented by all subclasses */
  public abstract void appearance(); 
}

class FerrariABC extends Car{
 public void  appearance(){

 }
}

class McLarenABC extends Car{
 public void  appearance(){

 }
}

class JaguarABC extends Car{
 public void  appearance(){

 }
}

class LamborghiniABC extends Car{
 public void  appearance(){

 }
}

class PorscheABC extends Car{
 public void  appearance(){

 }
}

class CarTest{
 public static void main(String args[]){
  FlyingCar obj1 = new CarCannotFly();
  FlyingCar obj2 = new CarCanFly();
  
  FerrariABC myFerrari = new FerrariABC();
  myFerrari.setFlyBehavior(obj1);
  myFerrari.fly();
  
  System.out.println("I can Change flying behavior at Run time also");
  
  myFerrari.setFlyBehavior(obj2);
  myFerrari.fly();
 }
}

Output
I Can't Fly
I can add flying behavior at Run time also
I Can Fly


                                                             Home

No comments:

Post a Comment