Strategy Pattern

Strategy Pattern is the behavioural pattern.

Often developer gets confused with Template and Starategy Pattern. For explanation I will use same Case Study we used in Template with few changes in requirement. Let’s understand the Startegy pattern before jumping to difference between Teamplate and Strategy.

Motive: Strategy Pattern defines a family of algorithms, encapsulates each one and makes them interchangeable. Subclasses decide how to implement steps in an algorithm.

Where To Use

  1. Many related classes differ only in their behavior
  2. Need different variants of an algorithm
  3. An algorithm uses data that clients shouldn’t know about. Use the Strategy pattern to avoid exposing complex, algorithm-specific data structures.
  4. A class defines many behaviors, and these appear as multiple conditional statements in its operations. Instead of many conditionals, move related conditional branches into their own Strategy class

Real World Example:

  • Swing GUI Text components
  • Java AWT

Benefits

  • Provides an alternative to subclassing the Context class to get a variety of algorithms or behaviors
  • Eliminates large conditional statements
    Provides a choice of implementations for the same behavior

Liabilities

  • Increases the number of objects
  • All algorithms must use the same Strategy interface

Case Study

Develop system to process flat file for a) Stock and b) Derivatives.

Requirement

  1. Validate File format/type against system configuration
  2. Stock/Derivative data can be stored in database or content repository (as XML)
  3. File can be routed to third party system Bloomberg (via SOAP) or other customer (JMS)
  4. Investment Bank can do below action
    Indus Bank: validate, store data (database) and route to Bloomberg
    USB Bank: validate, store (Repo) and route to Bloomberg
    ABC Bank: validate, store (DB) and route to other customer

Class Diagram: Please open class diagram in new window if problem occurs.

Strategy Pattern

Strategy Pattern

Explanation:

Strategy Pattern – This define family of algorithms, encapsulate each one and make them interchangable.

Behaviour/Operations:

  1. Validate – common method to validate File format/type (independent of investment type – Stock/Derivative)
  2. Parse and Store – parse data based on investment type (Stock/Derivative) and store within database or content repository system in XML format
  3. Route – file to third party system (via SOAP) or Content repository system

Interchangable algorithm – Store and Route. Behaviour can be dynamically set at runtime via composition. 
 

Class:

DataHandler Class – This class define common behaviour and behaviour to be implemented by subclasses. Also behaviour can be set at run time to store and route data.

package com.behavioral.strategy;

import java.util.HashSet;
import java.util.Set;

/**
 * Strategy Pattern – This define family of algorithms, encapsulate each one and
 * make them interchangable. <br>
 *
 * Interchangable algorithm – Store and Route. Dynamically at runtime via composition. <br>
 * 
 * This class define common behaviour and behaviour to be implemented by subclasses.
 * Also behaviour can be set at run time to store and route data.
 *
 * @author Shishir.Kumar
 */
public abstract class DataHandler {
 // Composition used to set dynamic behaviour at runtime
 Storage storage;
 Router router;
 static Set<String> validFileExtension = new HashSet<String>();
 static{
  validFileExtension.add(“csv”);
  validFileExtension.add(“txt”);
 }
 
 /**
  * Validate file path entension.
  * @param filePath String
  * @return true if valid
  */
 public boolean validate(String filePath){
  String extn = filePath.substring(filePath.lastIndexOf(“.”));
  return validFileExtension.contains(extn);
 }

 /**
  * Perform routing.
  * @param filePath String
  */
 public void performRouting(String filePath){
  getRouter().route(filePath);
 }
 /**
  * Sub class should override this method for specific behaviour.
  * @param filePath String
  */
 protected abstract void process(String filePath);
 
 /**
  * @return the storage
  */
 public Storage getStorage() {
  return storage;
 }

 /**
  * @param storage the storage to set
  */
 public void setStorage(Storage storage) {
  this.storage = storage;
 }

 /**
  * @return the router
  */
 public Router getRouter() {
  return router;
 }

 /**
  * @param router the router to set
  */
 public void setRouter(Router router) {
  this.router = router;
 }
 }

StockDataHandler, DerivativeDataHandler – Sub Class define interchangable algorithm – Store and Route.

package com.behavioral.strategy;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.util.StringTokenizer;

/**
 * StockDataHandler parse and store stock data within database or content
 * repository system, which is defined dynamically. <br>
 *
 * @author Shishir Kumar
 */
public class StockDataHandler extends DataHandler {

 /**
  * Override method for stock specific behaviour. This will store the stock data.
  * @param filePath String
  */
 @Override
 public void process(String filePath) {
   try {
    // Open the file that is the first
    FileInputStream fstream = new FileInputStream(filePath);
    // Get the object of DataInputStream
    DataInputStream in = new DataInputStream(fstream);
    BufferedReader br = new BufferedReader(new InputStreamReader(in));
    String strLine;
    // Read File Line By Line
    while ((strLine = br.readLine()) != null) {
     DataObject data = transformData(strLine);
     if(getStorage()!=null){
      // Data Storage is defined at runtime
      getStorage().store(data);
     }
    }
    // Close the input stream
    in.close();
   } catch (Exception e) {
    // Catch exception if any
    System.err.println(“Error: ” + e.getMessage());
   }
 }

 /**
  * Transform stock data.
  * @param strLine String
  * @return DataObject
  */
 private DataObject transformData(String strLine) {
  StringTokenizer tokenizer = new StringTokenizer(strLine,”,”);
  StockDataObject dataObject = null;
  if(tokenizer.hasMoreTokens() && tokenizer.countTokens()==5){
   dataObject = new StockDataObject();
   dataObject.setName(tokenizer.nextToken());
   dataObject.setOpenValue(new BigDecimal(tokenizer.nextToken()));
   dataObject.setHighValue(new BigDecimal(tokenizer.nextToken()));
   dataObject.setLowValue(new BigDecimal(tokenizer.nextToken()));
   dataObject.setCloseValue(new BigDecimal(tokenizer.nextToken()));
  }
  return dataObject;
 }

}

package com.behavioral.strategy;
/**
 * DerivativeDataHandler parse and store derivative data within database or content
 * repository system, which is defined dynamically. <br>
 *
 * @author Shishir Kumar
 */
public class DerivativeDataHandler extends DataHandler {

 /**
  * Override method for stock specific behaviour. This will store the derivative data.
  * @param filePath String
  */
 @Override
 protected void process(String filePath) {
  System.out.println(“Implement processing logic for derivative”);
 }
}

Storage and Router

package com.behavioral.strategy;
/**
 * Interface encapsulate behaviour to store business object.
 *
 * @author Shishir Kumar
 */
public interface Storage {
 /**
  * Store data
  * @param data DataObject
  */
 void store(DataObject data);
}

package com.behavioral.strategy;

/**
 * Store data within database.
 *
 * @author Shishir Kumar
 */
public class PersistenceStorage implements Storage {

 /**
  * Store data within database.
  * @param data DataObject
  */
 public void store(DataObject data) {
  // Persist information
  StockDataObject dataVal = (StockDataObject)data;
  log(“Data is stored in database”);
  log(“Stock Name:” + dataVal.getName());
  log(“High Value:” + dataVal.getHighValue().toString());
  log(“Low Value:” + dataVal.getLowValue().toString());
  log(“Open Value:” + dataVal.getOpenValue().toString());
  log(“Close Value:” + dataVal.getCloseValue().toString());
 }

 private void log(String str){
  System.out.println(str);
 }
}

package com.behavioral.strategy;

/**
 * Store data within content repository system in XML format.
 *
 * @author Shishir Kumar
 */
public class ContentRepoStorage implements Storage {

 public void store(DataObject data) {
  log(“Data converted to XML format using JAXB.”);
  log(“XML is stored in content repository system.”);
 }

 private void log(String str){
  System.out.println(str);
 }
}

package com.behavioral.strategy;
/**
 * Interface encapsulate behaviour to route business object.
 *
 * @author Shishir Kumar
 */
public interface Router {
 void route(String filePath);
}

package com.behavioral.strategy;

/**
 * This route request to Bloomberg as attachment using SOAP protocal. <br>
 *
 * @author Shishir Kumar
 *
 */
public class BloombergRouter implements Router{

 public void route(String filePath) {
  System.out.println(“Using SOAP protocal to send file as attachment!!!”);
 }

}

package com.behavioral.strategy;
/**
 * This implement default behaviour for routing request to third party via
 * JMS. <br>
 *
 * @author Shishir Kumar
 *
 */
public class ThirdPartyDefaultRouter implements Router {

 public void route(String filePath) {
  System.out.println(“Sending file over dedicated JMS Queue!!!”);
 }

}

Reference DataObject Class

package com.behavioral.template;

import java.io.Serializable;

/**
 * DataObject Interface.
 * @author Shishir Kumar
 */
public interface DataObject extends Serializable {

}

package com.behavioral.template;

import java.math.BigDecimal;

/**
 * Data Object for Stock.
 *
 * @author Shishir Kumar
 */
public class StockDataObject implements DataObject {

 private static final long serialVersionUID = 1L;
 private String name;
 private BigDecimal openValue;
 private BigDecimal highValue;
 private BigDecimal lowValue;
 private BigDecimal closeValue;
 
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public BigDecimal getOpenValue() {
  return openValue;
 }
 public void setOpenValue(BigDecimal openValue) {
  this.openValue = openValue;
 }
 public BigDecimal getHighValue() {
  return highValue;
 }
 public void setHighValue(BigDecimal highValue) {
  this.highValue = highValue;
 }
 public BigDecimal getCloseValue() {
  return closeValue;
 }
 public void setCloseValue(BigDecimal closeValue) {
  this.closeValue = closeValue;
 }
 public BigDecimal getLowValue() {
  return lowValue;
 }
 public void setLowValue(BigDecimal lowValue) {
  this.lowValue = lowValue;
 }
}

Client Class:

package com.behavioral.strategy;

/**
 * Simulate testing for below scenario: <br>
 * Indus Bank: validate, store data (database) and route to Bloomberg <br>
 * USB Bank: validate, store (Repo) and route to Bloomberg <br>
 * ABC Bank: validate, store (DB) and route to other customer <br>
 * XYZ Bank: validate and store (Repo) only<br>
 *
 * @author Shishir Kumar
 */
public class StrategyClient {
 public static void main(String[] args) {
  String filePath = “Strategy.csv”;
  // Simulate Indus Bank testing.
  DataHandler strategy = new StockDataHandler();
  // Set run time behaviour for storage and router
  strategy.setStorage(new PersistenceStorage());
  strategy.setRouter(new BloombergRouter());
  // Invoke logic to process
  System.out.println(“Simulating Indus Bank:”);
  simulate(filePath, strategy);

  // Invoke logic to process
  System.out.println(“Simulating USB Bank:”);
  strategy.setStorage(new ContentRepoStorage());
  simulate(filePath, strategy);
  
 }

 private static void simulate(String filePath, DataHandler strategy) {
  strategy.validate(filePath);
  strategy.process(filePath);
  strategy.performRouting(filePath);
 }
}

Sample File: Share.csv

Download this file and save as “Share.csv” within classpath.

Should Read: Template Pattern

Download Code: StrategyPattern.zip

Please share your feedback/query.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: