Home > Design Patterns > The Strategy Pattern

The Strategy Pattern

April 18th, 2008

I will get right to the point about this pattern. Everyone at some point in their code has a switch statement, that depending on the state of an object, you do some crap and it just looks like this:

1
2
3
4
5
switch(object.getType()){
   case Type1:amount=something;break;
   case Type2:amount=somethingelse;break;
   case Type3:etcetcetc;
}


Not only is this about as ugly as it gets, it makes it utterly useless when it comes to extensibility and have thrown out any hope of it being reusable. This is an example of tightly coupling functionality that varies to the object. Things like this are difficult to manage over time and every time you think of another case, you get to let this beast of a switch statement grow and grow and grow. So how do we avoid something like this?

This is where the Strategy Pattern comes in. One of the main strengths is it allows you to encapsulate the behavior of an object rather than placing that behavior into the object. This would allow you to not only easily switch out behaviors with ease, but also allow you to switch them out at runtime.

In our switch statement, we were concerned about the amount. Depending on the type, we are calculating the type differently. What we want to do is rather than implementing into our class, we want to just say ‘whatever you are, calculate your amount.’

First thing that we must do is setup an abstract class for our object. What we want to put in here are the behaviors of the object that will change.

1
2
3
4
5
6
7
8
9
10
public abstract class AmountObject {
   public AmountObject (){}
   public AmountStrategy amountStrategy;
   public void calculateAmount(){
      amountStrategy.getAmount();
   }
   public AmountStrategy setAmountStrategy(AmountStrategy as){
      amountStrategy = as;
   }
}

As you can see, its a simple class, all it has is an AmountStrategy object and something that calls getAmount() on it. For this example, lets just say all it does is output the amount. In a more real world example (which i would like to post for you later), we could pass in whatever parameters into the behavior into the function to do the calculations. Lets look how the behaviors will work. First we are going to have an interface for each different type of behavior to implement.

1
2
3
public interface AmountBehavior {
   public void getAmount();
}

Thats it. We have an interface with just its method. Now the implementation of the behavior.

1
2
3
4
5
6
public class AmountStrategyA implements AmountBehavior{
   public void getAmount() {
      //do some calculations. Usually you would pass in parameters for  this
      System.out.println("This is Strategy A");
   }
}

And for the sake of example, lets implement another one.

1
2
3
4
5
6
public class AmountStrategyB implements AmountBehavior{
   public void getAmount() {
      //do some calculations. Usually you would pass in parameters for  this
      System.out.println("This is Strategy B");
   }
}

Now, when we extend our abstract class, we will be able to assign either one of these strategies. As I said earlier, we have encapsulated the behavior of our object rather than coding it straight into our implementation. So lets see how it will work out for us.

1
2
3
4
5
6
public class AmountStrategyImpl extends AmountStrategy{
   public AmountStrategyImpl(){
      amountBehavior = new AmountStrategyA ();
      //whatever other fields that need to be here.
   }
}

So now we have our implementation with AmountStrategyA. Once again, its pretty straight forward. We have extended our abstract class that has default functionality and fields already there. From our abstract class, we assign the amountBehavior to it. Finally, lets see what it looks like in action.

1
2
3
4
5
6
public class AmountStrategyExample extends AmountObject {
   public static void main(String[] args) {
      AmountStrategyImpl amountStrategy = new AmountStrategyImpl ();
      amountStrategy.getAmount();
   }
}

If you were to compile all these classes and run them, it would output “This is Strategy A”. Now, what we have done is totally isolate the behavior of our object into separate classes and allowed us to assign them to the object depending on the requirements. There is one function that I did not explain in our abstract method though, which is the setAmountStrategy function. What this allows us to do is reassign the strategy AT runtime. So lets say for whatever reason you wanted to change the strategy on how you calculate your amount (IE: You make more money and now your taxes are calculated differently). Add this line at the end of the implementations:

1
2
   amountStrategy.setStrategy(new AmountStrategyB());
   amountStrategy.getAmount();

Now it will output “This is Strategy B”. Pretty cool huh? :)

If you were to google Strategy Pattern, one phrase that you will see repeated is “Program for an interface, not for an implementation”, which is exactly what has happened here. We have taken the behavior of the object and placed it in an abstract class and in an interface. We then took the behavior AWAY from the implementation. The implementation should never care how the amount is calculated. All it wants is the amount. The main thing to keep in mind when coding these is think about your object and ask ‘what behavior is static and what behavior is dynamic?’ Take what is dynamic and encapsulate it and take it away from your main object. Then in the implementation, assign the behavior.

Hope this article was helpful. Also if anyone wants to through a heads up to me a good plugin to format the code. I have tried 3 and none seem to work properly (one deleted half of this post grrr). Let me know and I hope you have enjoyed the article!

Design Patterns

  1. May 11th, 2009 at 07:39 | #1

    This is exactly what I stumbled upon a few days ago. Err, what I whish I had found. But really I found a couple of if and switch statements that crumple up lots of functionality into a single method… :-(

  2. May 11th, 2009 at 14:09 | #2

    I reached this post from a link on a new one, but it seems that there is some problems with naming. The AmountStrategy class is not implemented anywhere (maybe it has been renamed in AmountBehaviour).

  3. Geoff Denning
    August 29th, 2009 at 13:47 | #3

    Thanks for this great example of the Strategy pattern, this helped me to understand this pattern much better than any other reference I’ve found online so far.

    I just wanted to point out a few minor mistakes in the code, which had me a bit confused at first:

    * In the AmountObject abstract class, setAmountStrategy should return void.
    * The AmountBehavior interface should be named AmountStrategy.
    * The AmountStrategyImpl class should extend AmountObject (not AmountStrategy).
    * The AmountStrategyExample class should not extend anything.
    * In the AmountStrategyExample class, the amountStrategy.getAmount(); line should actually say amountStrategy.calculateAmount();

  4. Anonymous
    May 1st, 2010 at 02:26 | #4

    Amazing post, you’ve helped me understand the strategy!

  5. October 19th, 2011 at 11:18 | #5

    Thank you for this article. It helped me rethink a big switch statement I have. However, it still appears you would need a switch statement to handle the choice of strategy. Correct me if I am wrong (please do, because I would like a better way), but in the situation you mentioned, you would need to change the strategy depending on salary and this would require a switch or check of some sort.

  6. October 19th, 2011 at 11:20 | #6

    To add to my previous comment: Is there a way to determine the strategy without requiring a switch? Would it be possible to say: “This value was passed in, now who wants to deal with it?”

  1. No trackbacks yet.