04.02.08

A much better Strategy Pattern

Posted in Design Patterns, Java at 2:19 am by Administrator

In words of Gang Of Four design patterns Book and from Wikipedia, definition of Strategy Pattern is as follows :

Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.The strategy pattern is useful for situations where it is necessary to dynamically swap the algorithms used in an application. The strategy pattern is intended to provide a means to define a family of algorithms, encapsulate each one as an object, and make them interchangeable. The strategy pattern lets the algorithms vary independently from clients that use them.

As i always do, i believe in writing code rather than writing passages of theory. First I will show Simple implementation of strategy and compare it with What it my code would look like without strategy pattern, then i will tell you guys how to tweak my Strategy pattern to allow removal of some of the “hard wired” initializations. So lets get on with it, we’ve got a lot of ground to cover.


public interface IStrategy extends Serializable{

public Object operation(Object firstOperand, Object secondOperand);

}

Once again to keep things simple, i have stripped all java documentation etc. (And not to mention that it somehow breaks the flow on Word press). So as you can make out, we have a strategy interface; It has one method namely operation which takes two operands. The “Whats” and “Hows” of operation are left to implementors. This strategy helps in isolating the algorithm itself and allows it be to implemented in different ways. If you ask me, by now you might already know what strategy pattern is, but devil is in the details as they say.

public class MultiplicationStrategy implements IStrategy {

private static final long serialVersionUID = 1L;
private static final int VALUE_ZERO = 0;

/**
* {@inheritDoc}
*
*/
public Object operation(Object firstOperand,
Object secondOperand) {

Integer opOne = VALUE_ZERO;
Integer opTwo = VALUE_ZERO;

if (firstOperand instanceof Integer
&& secondOperand instanceof Integer) {

opOne = castOperand(firstOperand);
opTwo = castOperand(secondOperand);

}

// return the sum of two integer
return multiplyOperands(opOne, opTwo);
}

// casts the operand without checking anything
//... this assumes that a check was made already
private final Integer castOperand(final Object firstOperand) {
Integer opOne;
opOne = ((Integer) firstOperand);

// return here
return opOne;
}

// multiplies two operands.
private final int multiplyOperands(final Integer opOne,
final Integer opTwo) {
return opOne * opTwo;
}

}

^^ The above is an implementation of IStrategy, likewise (without showing any further strategies) assume that we have SumStrategy, DivisionStrategy. (Division will off course have that divide by 0 logic etc. but thats not our concern).

Next we have something called a Context now context class holds a reference to a IStrategy type with a setter and a getter for the same. This context will later be used to tie a strategy to applied in a particular scenario. ( For example if client wants to multiply two numbers, a multiplication strategy will be set on this class and so on ).


public class Context {

private IStrategy strategy;
private static int counter = 0;

// private constructor.
private Context(){
}

/**
* returns the context instance
* initialized with Strategy type.
*
* @param strategy
* strategy instance to be set for this context.
*
* @return context
* singleton context instance
*/
public static Context getInstance(){

// return instance
return new Context();
}

/**
* gives the strategy for this context.
*
* @return strategy
* the strategy to get
*/
public IStrategy getStrategy() {

if(counter == 0){
throw new IllegalStateException(" initialization of context not complete...");

}

// return
return strategy;
}

/**
* sets the strategy for this context.
*
* @param strategy
* strategy to be set.
*/
public void setStrategy(IStrategy strategy) {
this.strategy = strategy;
counter++;

}

Now for the real deal, lets see how client invokes the same and how everything falls in place.


public class Test {

/**
*
*
* @param args
* arguments to be passed.
*
*/
public static void main(String[] args) {

// $Id - Step 1 : get the Context instance and pass in Strategy type.
Context context = Context.getInstance();

// $Id - State ( Context ) : division strategy being set
context.setStrategy(new DivisionStrategy());

// perform the operation :
//Notice that i am not calling any specific operations ( like sum( ) or division( ) etc.)
Integer result = (Integer)context.getStrategy().operation(400, 200);

// print
System.out.println("( Result of Division strategy was ) --> ( " + result + " ) ");

// $Id - Step 2 : get the Context
// instance and pass in Strategy type.
Context sumContext = Context.getInstance();

// $Id - State ( Context ) : Sum strategy being set
sumContext.setStrategy(new SumStrategy());

// perform the operation
// Notice that i am not calling any specific
// operations ( like sum( ) or division( ) etc.)
Integer sumResult = (Integer)sumContext.getStrategy().operation(400, 200);

// print
System.out.println("( Result of Sum strategy was ) --> ( " + sumResult + " ) ");

// $Id - Step 3 : get the Context instance and pass in Strategy type.
Context multiplyContext = Context.getInstance();

// $Id - State (Context) : Multiplication
multiplyContext.setStrategy(new MultiplicationStrategy());

// perform the operation
// Notice that i am not calling
// any specific operations ( like sum( ) or division( ) etc.)
Integer multiplyResult = (Integer)multiplyContext.getStrategy().operation(400, 200);

// print
System.out.println("( Result of Multiplication strategy was ) --> ( " + multiplyResult + " ) ");

}

Here’s what we are doing above in a nutshell :

  1. Initialize the context
  2. Set the strategy
  3. get the strategy that was set and perform operation

Whats the difference you may ask? well for one, As a client i only used operation( ) and nothing like Multiplication or division etc. (Off course i can think of dozens of other better examples than above, but simplicity is the key to understanding the concept).

Now It is really easy to see what my code would be like without using a strategy, in a nutshell it would be something like :


class Test{
....
main(String[] args){

client.performOperation("OPERATION_TYPE");

}

...

performOperation(String operationType){

if(operationType.trim().equalsIgnoreCase("blah_blah){
// do blah blah operation

}else if(operationType.trim().equalsIgnoreCase("blah){
// do blah blah blah operation

}

... // and so on
}

}

One can obviously see separation of concerns here and cleanliness in the code. But thats not all … Somehow i don’t find my strategy pattern satisfying. To me, we are using (in setting Strategies in context as you may recall, refer above if you don’t), but before using them we do an explicit set. But thats not what i want. I want something to wire this dependency on fly based on some criteria given by the client. (.A.K.A Dependency Injection ). I”ll show how to do that and modify the above to test to make it much better … so stay tuned! :)

Regards
Vyas, Anirudh

1 Comment »

  1. Programming Thoughts @ Work » A much better Strategy Pattern - Part II said,

    April 5, 2008 at 1:34 am

    […] To give you a little refresher, In my last post we discussed, Strategy pattern briefly (refer to : Strategy Pattern - Part I), we create an IStrategy interface ( with operation method in it, taking two parameters (arguments […]

Leave a Comment