Thursday, April 6, 2017

Strategy Design Pattern in Java

INTRODUCTION
The strategy design pattern will choose the different algorithms or implementations dynamically. We may have different strategies for a requirement, but dynamically it can be accessed based on the need.  In the real world, a different person will have a different solution for the same problem, but based on the need anyone of the solution will be utilized.
USECASE
Assembling different types of vehicles.

IMPLEMENTATION
PROBLEM
Consider we want to assemble the bike based on the type client wants. The possible implementation would be below
  1. package jbr.strategypattern.problem;  
  2.   
  3. import jbr.common.VehicleType;  
  4. import jbr.common.model.Vehicle;  
  5.   
  6. public class AssembleVehicle {  
  7.   
  8.   public static void main(String[] args) {  
  9.     Vehicle car = assemble(VehicleType.CAR);  
  10.     System.out.println(car.getVehicleType());  
  11.   }  
  12.   
  13.   public static Vehicle assemble(VehicleType vehicleType) {  
  14.     Vehicle vehicle = null;  
  15.     switch (vehicleType) {  
  16.     case CAR:  
  17.       vehicle = new Vehicle(4"honda", VehicleType.CAR, 100000);  
  18.       break;  
  19.     case BIKE:  
  20.       vehicle = new Vehicle(2"hero", VehicleType.BIKE, 300000);  
  21.       break;  
  22.     case BUS:  
  23.       vehicle = new Vehicle(4"ashok leyland", VehicleType.BUS, 1300000);  
  24.       break;  
  25.     default:  
  26.       break;  
  27.     // add implementations for new type of vehicles  
  28.     }  
  29.   
  30.     return vehicle;  
  31.   }  
  32. }  

SOLUTION
The issue with the above code is, it is not easily maintainable. We need to alter a lot of code if any new strategy needs to be added in future. The solution would be below.
Create an Enum for the different type of vehicles.
  1. package jbr.common;  
  2.   
  3. public enum VehicleType {  
  4.   CAR, BIKE, BUS;  
  5. }  
Create a model for Vehicle.
  1. public class Vehicle {    
  2.   private int noOfWheels;    
  3.   private String manufacturer;    
  4.   private VehicleType vehicleType;    
  5.   private int price;    
  6.       
  7.   //constructor    
  8.   //getters and setters    
  9. }   
Create a strategy (interface) for bike assembling.
  1. package jbr.strategypattern.solution;  
  2.   
  3. import jbr.common.model.Vehicle;  
  4.   
  5. public interface Assembler {  
  6.   
  7.   Vehicle assemble();  
  8. }  
Now create separate strategies for Car, Bike and Bus.
Car assembling strategy.
  1. package jbr.strategypattern.solution;  
  2.   
  3. import jbr.common.VehicleType;  
  4. import jbr.common.model.Vehicle;  
  5.   
  6. public class CarAssembler implements Assembler {  
  7.   
  8.   @Override  
  9.   public Vehicle assemble() {  
  10.     return new Vehicle(4"honda", VehicleType.CAR, 100000);  
  11.   }  
  12. }  

Bike assembling strategy.
  1. package jbr.strategypattern.solution;  
  2.   
  3. import jbr.common.VehicleType;  
  4. import jbr.common.model.Vehicle;  
  5.   
  6. public class BikeAssembler implements Assembler {  
  7.   
  8.   @Override  
  9.   public Vehicle assemble() {  
  10.     return new Vehicle(2"hero", VehicleType.BIKE, 300000);  
  11.   }  
  12. }  

Bus assembling strategy.
  1. package jbr.strategypattern.solution;  
  2.   
  3. import jbr.common.VehicleType;  
  4. import jbr.common.model.Vehicle;  
  5.   
  6. public class BusAssembler implements Assembler {  
  7.   
  8.   @Override  
  9.   public Vehicle assemble() {  
  10.     return new Vehicle(4"ashok leyland", VehicleType.BUS, 1300000);  
  11.   }  
  12. }  
Now create a client which accepts different strategies dynamically based on the need of the client.
  1. package jbr.strategypattern.solution;  
  2.   
  3. import jbr.common.VehicleType;  
  4. import jbr.common.model.Vehicle;  
  5.   
  6. public class MyVehicle {  
  7.   
  8.   public static void main(String[] args) {  
  9.     Vehicle car = assemble(VehicleType.CAR);  
  10.     System.out.println(car.getVehicleType());  
  11.   }  
  12.   
  13.   public static Vehicle assemble(VehicleType vehicleType) {  
  14.     CarAssembler carAssembler = new CarAssembler();  
  15.     BikeAssembler bikeAssembler = new BikeAssembler();  
  16.     Vehicle vehicle = null;  
  17.   
  18.     switch (vehicleType) {  
  19.     case CAR:  
  20.       vehicle = carAssembler.assemble();  
  21.       break;  
  22.     case BIKE:  
  23.       vehicle = bikeAssembler.assemble();  
  24.       break;  
  25.     default:  
  26.       break;  
  27.     // add implementations for new type of vehicles  
  28.     }  
  29.   
  30.     return vehicle;  
  31.   }  
  32.   
  33. }  

Still we have all the logic to call the different strategies into the client code itself, now we will try to enhance our client code lighter by creating a factory for assembling different vehicles based on the type.
Create a factory.
  1. package jbr.strategypattern.solution;  
  2.   
  3. import jbr.common.VehicleType;  
  4.   
  5. public class AssemblerFactory {  
  6.   
  7.   public static Assembler assemble(VehicleType vehicleType) {  
  8.     switch (vehicleType) {  
  9.     case CAR:  
  10.       return new CarAssembler();  
  11.     case BIKE:  
  12.       return new BikeAssembler();  
  13.     case BUS:  
  14.       return new BusAssembler();  
  15.     default:a  
  16.       break;  
  17.     }  
  18.   
  19.     return null;  
  20.   }  
  21. }  

Now our enhanced client code will be.
  1. package jbr.strategypattern.solution;  
  2.   
  3. import jbr.common.VehicleType;  
  4. import jbr.common.model.Vehicle;  
  5.   
  6. public class MyVehicleEnhanced {  
  7.   
  8.   public static void main(String[] args) {  
  9.     Vehicle vehicle = assemble(VehicleType.CAR);  
  10.     System.out.println(vehicle.toString());  
  11.   
  12.     vehicle = assemble(VehicleType.BIKE);  
  13.     System.out.println("\n" + vehicle.toString());  
  14.   
  15.     vehicle = assemble(VehicleType.BUS);  
  16.     System.out.println("\n" + vehicle.toString());  
  17.   
  18.   }  
  19.   
  20.   public static Vehicle assemble(VehicleType vehicleType) {  
  21.     return AssemblerFactory.assemble(vehicleType)  
  22.         .assemble();  
  23.   }  
  24. }  

OUTPUT

Type: CAR
No Of Wheels: 4
Manufacturer: honda
Price: 100000

Type: BIKE
No Of Wheels: 2
Manufacturer: hero
Price: 300000

Type: BUS
No Of Wheels: 4
Manufacturer: ashok leyland
Price: 1300000

Hope this example clarifies the Strategy Design Pattern. Please share your thoughts in comment box.
Happy Knowledge Sharing!!!

No comments :

Post a Comment