When and why should the Strategy Pattern be used?

User1 picture User1 · Nov 10, 2009 · Viewed 23.1k times · Source

When would the Strategy Pattern be used?

I see client code snippets like this:


class StrategyExample {

    public static void main(String[] args) {

        Context context;

        // Three contexts following different strategies
        context = new Context(new ConcreteStrategyAdd());
        int resultA = context.executeStrategy(3,4);

        context = new Context(new ConcreteStrategySubtract());
        int resultB = context.executeStrategy(3,4);

        context = new Context(new ConcreteStrategyMultiply());
        int resultC = context.executeStrategy(3,4);

    }

}

and it looks like you could just refactor it to this:


class StrategyExample {

    public static void main(String[] args) {
         // Three contexts following different strategies
        int resultA =new ConcreteStrategyAdd().execute(3,4);
        int resultB =new ConcreteStrategySubtract().execute(3,4);
        int resultC =new ConcreteStrategyMultiply().execute(3,4);
    }

}

The first section of code was taken directly from the wikipedia page. One big difference is the context goes away, but it wasn't doing anything in the example anyway. Maybe someone has a better example where Strategy makes sense. I usually like design patterns but this one seems to add complexity without adding usefulness.

Answer

Tendayi Mawushe picture Tendayi Mawushe · Nov 10, 2009

The problem with toy examples such as this is that it is often easy to miss the point. In this case, the code could indeed be just implemented as you have shown. In a strategy pattern, the main value is in being able to switch out different implementations for different situations.

The example you have is only illustrating the objects in the pattern and the interactions between them. Imagine instead that you had a component that renders graphs for a website depending on whether it was a desktop or a smartphone on the other end you would have some code that would detect the type of browser the create and set the strategy on another component that could use the strategy object in some complex code that would not need to be duplicated and would do the work in both situations leaving the details of the actual drawing of the graph to the appropriate strategy object:

interface GraphStrategy {
    Image renderGraph(Data graphData);
}

class BigGraphStrategy implements GraphStrategy {
    ...
}

class SmallGraphStrategy implements GraphStrategy {
    ...
}

Then in some other code:

GraphStrategy graphStrategy;

if (phoneBrowser == true) { 
    graphStrategy = new SmallGraphStrategy();
} else {
    graphStrategy = new BigGraphStrategy();
}

The rest of your application code can then just use graphStrategy.renderGraph() without having to know whether full or small image rendering is being performed.