Strategy pattern

From GPWiki
Jump to: navigation, search

The Strategy pattern shows how to supply a variant of an algorithm by wrapping it in a class.

Definition

Problem

You want to be able to change how an algorithm works after the class that uses the algorithm has been finalized.

Context

  1. A class (the context class) can benefit from using different variant of the same algorithm.
  2. Users of the context class may want to supply a custom version of the algorithm.

Solution

  1. Define a strategy interface that is an abstraction of the algorithm.
  2. Create concrete classes that implement the strategy interface and define the algorithm.
  3. The context class supplies a way of passing a strategy object to it.
  4. When the strategy class need to use the algorithm, it invokes the method that holds the algorithm from the passed strategy object.


Formal class diagram for the strategy pattern


Example Usage

Imagine that you are developing a roleplaying game where you want to move your characters around on the map. You are interested in supplying different algorithms for movement for different types of characters. For instance, a human character needs to avoid collision with trees etc. while a ghost character can move right through buildings and a wizard character can teleport himself.

Class diagram for a unit moving system using the strategy pattern


Pseudo code:

class Unit
{
    private MoveAlgorithm moveAlg;
 
    public Unit()
    {
        moveAlg = new AStar();
    }
 
    public Unit( MoveAlgoritm ma )
    {
        moveAlg = ma;
    }
 
    public setMoveAlgorithm( MoveAlgorithm ma )
    {
        moveAlg = ma;
    }
 
    public moveTo( int toX, int toY )
    {
        String moves = moveAlg.getMoves( currentPosX, currentPosY, toX, toY );
        print( "Moving unit: " + moves );
    }
}
 
interface MoveAlgorithm
{
    String getMoves( int fromX, int fromY, int toX, int toY );
}
 
class BirdFlight implements MoveAlgorithm
{
    public String getMoves( int fromX, int fromY, int toX, int toY )
    {
        return "Moving in birdflight to position (" + toX + "," + toY + ")";
    }
}
 
class AStar implements MoveAlgorithm
{
    public String getMoves( int fromX, int fromY, int toX, int toY )
    {
        return "Moving according to the A* algorithm to position (" + toX + "," + toY + ")";
    }
}

Test:

Unit player = new Unit(); // A* movement algorithm is on by default
player.moveTo( 50, 50 );
 
// The player is killed and is transformed into a ghost.
print( "Player is killed!" );
 
// Therefore we apply the movement algorithm for the ghost character.
player.setMovementAlgorithm( new BirdFlight() );
player.moveTo( 70, 70 );

Output:

Moving unit: Moving according to the A* algorithm to position (50,50)
Player is killed!
Moving unit: Moving in birdflight to position (70,70)

Using the strategy pattern can have many benefits and can vastly improve the flexibility of your classes.


Another usage of the strategy pattern could be supplying an algorithm for drawing the unit instead. That system could look like the following class diagram shows and would in practice work almost exactly like the previous example.

Class diagram for a unit drawing system using the strategy pattern

Additional Information