Monday, October 4, 2010

Design Patterns in Java - Strategy

Introduction

Strategy pattern is alternative to Template method. But in case of Strategy pattern we use interface instead of abstract class. Please read more about this type of encapsulating logic in post about Template method if you are interested. Here we will here just show differences in correlation to TM.

You can download example of this Java code from my repository on google code:
https://code.google.com/p/codingwithpassionblog/source/browse/trunk/src/org/codingwithpassion/patterns/strategyMethod/DecorateData.java

Example

So in this case, class that knows the algorithm is not an abstract superclass, but a concrete class that uses a helper that implements an interface defining individual steps. You will use this type of pattern if you need to use concrete inheritance for some other purpose (because as we all knows Java and similar languages does not support multiple inheritance), or you just like this approach better because you are not forced to inherit from abstract class. Whatever is you reason, here is example:
/**
 * Concrete Object implementation. 
 * Here we implement workflow.
 */
class CreateObject {
 
 protected Object[] datas = {"Kimmi", "Zuco", 1, 21};
 
 public void setData(Object[] data) {
  CreateObject.this.datas = data;
 }
 
 /**
  * Algorithm that control flow (IOC - Inversion of Control).
  * @return Object String representation. 
  */
 public String decorate(DecoratorHelper helper) {
  StringBuilder sb = new StringBuilder();
  helper.objectStart(sb);
  
  for (int i = 0; i < datas.length; i++) {
   Object data = datas[i];
   if (data instanceof String) {
    helper.stringValue(sb, data, i);
   } else if (data instanceof Integer) {
    helper.numberValue(sb, data, i);
   }
  }
  helper.objectEnd(sb);  
  return sb.toString();
 }   
}
/**
 * Helper interface to which we defer individual steps.
 *
 */
interface DecoratorHelper {
 
 void objectStart(StringBuilder sb);
 
 void objectEnd(StringBuilder sb);
 
 void stringValue(StringBuilder sb, Object value, int indx);
 
 void numberValue(StringBuilder sb, Object value, int indx);
}

/**
 * Object creation for JSON objects;
 *
 */
class JSONObject implements DecoratorHelper {
 
 public void objectStart(StringBuilder sb) {
  sb.append("\"Object\":").append("\n{");
 }
 
 public void objectEnd(StringBuilder sb) {
  sb.append("\n}");
 }
 
 public void stringValue(StringBuilder sb, Object value, int indx) {
  sb.append("prop")
    .append("\"").append(indx).append("\":")
    .append("\"").append(value).append("\",")
    .append("\n");
    
 }
 
 public void numberValue(StringBuilder sb, Object value, int indx) {
  sb.append("prop")
    .append("\"").append(indx).append("\":")
    .append(value).append(",")
    .append("\n");
 }
}

/**
 * Object creation for xml objects.
 *
 */
class XmlObject implements DecoratorHelper {
 
 public void objectStart(StringBuilder sb) {
  sb.append("").append("\n");
 }
 
 public void objectEnd(StringBuilder sb) {
  sb.append("");
 }
 
 public void stringValue(StringBuilder sb, Object value, int indx) {
  sb.append("")
    .append("prop")
    .append(indx)
    .append("")
    .append(value)
    .append("")
    .append("")
    .append("\n");  
 }
 
 public void numberValue(StringBuilder sb, Object value, int indx) {
  sb.append("")
    .append("prop")
    .append(indx)
    .append("")
    .append(value)
    .append("")
    .append("")
    .append("\n");  
 }
 
}
/**
 * Testing...
 *
 */
public class DecorateData {
 
 public static void main(String[] args) {
  CreateObject xml = new CreateObject();
  
  System.out.println(xml.decorate(new XmlObject()));
 }
 
}
37 - 46: First we move template methods into an interface. Definition is same as in previous example.
52 - 76, 82 - 114: In implementation of our interface we do not need to subclass anything anymore. But note that we must change access mode of method to public because this time we will to access them from outside class hierarchy.
17: Note that we need to provide interface type to our template method. This type will be substitute to concrete instance of class at runtime (Polymorphism is great stuff!). Method is exactly same as in TM example.

Which to choose?

This approach is more complex, but is more flexible. This is classic example of trade-off between concrete inheritance and delegating to an interface. Decision what to choose is completely up to you and may be influenced by circumstances like: Class implementing steps needs its own inheritance hierarchy, how many steps are involved, how many different implementation will you have...

No comments:

Post a Comment