Last week we looked at one of the structural design patterns, the adapter pattern. This week we’ll look at the Strategy design pattern.
Strategy Pattern as a Behavioural Pattern
The Strategy pattern is a behavioural pattern. These are patterns that are concerned with communication between objects and encapsulating processes.
The intent of the Strategy pattern is to define a family of algorithms, encapsulate each one and make them interchangeable.
Strategy Pattern: Example
Let’s say we’re creating a first person shooter game. Amongst other things, the game will have monsters that can move through the modelled world, whether it is a maze, a building, a scorched Earth. These monsters can be aliens, zombies, robots, mutant creatures or anything else that we can think of. The monsters can hunt and attack the players. Obviously we should have a common Monster
interface, which could be coded as follows:
public interface Monster { public void move(); public void hunt(); }
We will code our concrete classes implementing this interface. Here is a snippet of code from the Zombie
class; the others will be similar:
public class Zombie implements Monster { public void move() { // appropriate code } public void hunt() { // appropriate code } }
The decision of how a monster can move or hunt can be based on the initial game level chosen by the player. This can also change as a player gets better and more skilled. This means we need to code up multiple different copies of the same monster for different skill levels. If we have a number of different monsters with the same way of moving and hunting, we’d have to do even more copying and pasting. A nightmare for testing and maintenance!
Strategy Pattern to the Rescue
A better way to model the movement and hunting mechanisms is to separate the algorithm for moving and hunting from that of the monsters themselves. We can then drop in a suitable movement algorithm whenever we create a monster. The algorithm itself will determine the movement. The first step is to create an appropriate interface for this algorithm:
public interface MovementStrategy { public void move() ; public void hunt() ; }
We would then create a MovementStrategy
instance field within a Monster
, and delegate the movement and hunting to the contained object:
public class Zombie implements Monster { private MovementStrategy strategy; public Zombie(MovementStrategy strategy) { this.strategy = strategy; } @Override public void move() { strategy.move(); } @Override public void hunt() { strategy.hunt(); } }
The intent of the Strategy design pattern is to define a family of interchangeable algorithms. This will allow the movement algorithm to vary independently from any of the classes that use it. We’ll create as many concrete classes implementing the MovementStrategy
interface as necessary. Here are a few appropriately implemented concrete classes:
public class SlowShufflingMovement implements MovementStrategy { public void move() { // appropriate code } public void hunt() { // appropriate code } } public class FastHunterKillerMovement implements MovementStrategy { public void move() { // appropriate code } public void hunt() { // appropriate code } }
When we create new monsters at the beginning of the game, or a new level, we can instantiate a class with the appropriate movement behaviours and pass it in to the monsters, as follows:
// Starting up the game; the level determines the movements ... MovementStrategy strategy = new SlowShufflingMovement(); Monster zombie = new Zombie(strategy); zombie.move(); // moves slowly // OR MovementStrategy strategy = new FastHunterKillerMovement(); Monster zombie = new Zombie(strategy); zombie.move(); // moves fast
As you can see, this is relatively simple pattern to understand and implement.
What’s next?
In the weeks ahead, we’ll continue examining some of the more useful design patterns. Stay tuned!
I’m always interested in your opinion, so please leave a comment. Your feedback helps me write tips that help you.