Developing with a strategy

This article was originally published in VSJ, which is now part of Developer Fusion.
Developers learn about inheritance very early on in their careers, and thenceforth it becomes a core tool that they use when designing and writing applications. Consequently, all too often they seek to find inheritance relationships where none exist, or perhaps more subtly they end up creating class hierarchies that start to fail as newer and related types get added to the application.

In this article we’re going to look at how using composition, rather than inheritance, can sometimes make the code easier to maintain and extend. Specifically, we’re going to examine the well-established GoF Strategy design pattern.

The Scenario

Imagine, for a moment, that you’re working for a company that’s been contracted to design a simulation application for the Army that will be used to help train senior officers in how to manage their troops on the battlefield. Your initial task is to design the type hierarchy for the different types of combat unit that will be involved, which include:
  1. Infantry
  2. Armoured units (tanks)
  3. Artillery
All the units need to be able to move, fight (a useful trait in a combat unit) and be able to be displayed as an icon on a map. So you sit down and ponder the problem for a short period of time, and possibly come up with the following simplified model:
public abstract class CombatUnit
{
	public abstract void DisplayIcon(
		Point location );
	public abstract void Move();
	public abstract void Fight();
	// other items elided for clarity
}
// the derived types
public class InfantryUnit : CombatUnit
{
	public override void Display(
		Point location ) {}
	public override void Move() {}
	public override void Fight() {}
}
public class ArmouredUnit : CombatUnit
{
	// overrides of the three methods
}
public class ArtilleryUnit :
	CombatUnit
{
	// overrides of the three methods
}
At first glance, this appears to be a reasonable implementation that meets the spec, so you code up the prototype and take it off to the MoD for review. Everything appears to be going well up until one of the evaluating officers says:

“Hmm, this is pretty good, but maybe we forgot to mention that we actually have three different types of infantry: airborne, light and mechanized. They all fight the same way, but how they move in the combat zone is different: the airborne guys fly in, the light infantry walk and the armoured infantry go in tracked AFVs. We also have airborne and self-propelled artillery. And guess what? The airborne artillery is moved by air and the self-propelled artillery uses tracked vehicles. Please make sure that the simulation reflects these requirements. Thanks.”

Revising the prototype

So you head off back to your office to apply this new information to your design, and come up with the following:
public abstract class CombatUnit
{
	public abstract void Display(
		Point location );
	public abstract void Move();
	public abstract void Fight();
	// other items elided for clarity
}
// the derived types
public abstract class InfantryUnit :
	CombatUnit
{
	public override void Display(
		Point location ) {}
	public override void Fight() {}
}
public class AirborneInfantryUnit :
	InfantryUnit
{
	public override void Move() {}
	/* Code duplicated with
		AirborneArtillery */
}
public class MechanizedInfantryUnit :
	InfantryUnit
{
	public override void Move() {}
	/* Code duplicated with
		ArmouredUnit,
		SelfPropelledArtillery */
}
public class LightInfantryUnit :
	InfantryUnit
{
	public override void Move() {}
}
public class ArmouredUnit : CombatUnit
{
	// overrides of all three methods
}
public abstract class ArtilleryUnit :
	CombatUnit
{
	public override void Display(
		Point location ) {}
	public override void Fight() {}
}
public class AirborneArtilleryUnit :
	CombatUnit
{
	public override void Move() {}
	/* Code duplicated with
		AirborneInfantry */
}
public class SelfPropelledArtilleryUnit : CombatUnit
{
	public override void Move() {}
	/* Code duplicated with
		ArmouredUnit,
		MechanizedInfantry */
}
Again, this is a pretty accurate model of the requirements, but you’d naturally be concerned about the highlighted lines (which also have “Code duplicated” comments next to them), because code duplication is never something that we’d strive to achieve: it requires extra testing and debugging and thus increases ongoing maintenance.

It therefore would appear that plain old boring inheritance is starting to make life more, rather than less, difficult. Fortunately, there is a way out of this inheritance trap: a design pattern called the Strategy pattern. So let’s take a look at it now.

The Strategy design pattern

Interestingly, we can learn something about the Strategy pattern from the symbols that NATO forces use when plotting units on maps.

As you can see from Figure 1, the symbol for mechanized infantry is composed out of the symbols for infantry and armoured units; and the symbol for self-propelled artillery is similarly composed using the symbols for armoured and artillery units. This idea of composition is at the heart of the Strategy pattern, where we build objects out of other parts in order to give them the required behaviours.

Figure 1
Figure 1: Relevant NATO App-6A Map Symbols (for friendly forces)

Defining the movement behaviours

In this case, we’re going to focus on how a unit moves and extract those different movement behaviours into a separate set of types. A few moments work and we come up with the following hierarchy:
public interface IMovementBehaviour
{
	void Move();
}
public class WalkMovementBehaviour :
	 IMovementBehaviour
{
	public void Move()
	{
		/* Foot slogging code here */
	}
}
public class
	TrackedMovementBehaviour :
	IMovementBehaviour
{
	public void Move()
	{
	/* Tracked simulation code here */
	}
}
public class
	AirborneMovementBehaviour :
	IMovementBehaviour
{
	public void Move()
	{
		/* Helicopter / plane
			simulation code here */
	}
}
This yields a set of movement behaviours that we can apply to any type of combat unit.

Implementing the Strategy pattern

We now need a way to use these behaviours from our combat units. The way that we go about doing this is very straightforward, namely:
  1. Have our type implement the IMovementBehaviour interface
  2. Use a field to hold a reference to a concrete movement behaviour object
  3. Delegate the calls through to the encapsulated object
Taking this approach to the CombatUnit class yields the following results:
public abstract class CombatUnit :
	IMovementBehaviour
{
	private IMovementBehaviour
		movementBehaviour;
	public abstract void Display();
	public abstract void Fight();
	public void Move()
	{
		movementBehaviour.Move();
	}
	public CombatUnit(
		IMovementBehaviour
		movementBehaviour )
	{
		this.movementBehaviour =
			movementBehaviour;
	}
}
public class InfantryUnit : CombatUnit
{
	public InfantryUnit(
		IMovementBehaviour
		movementBehaviour )
		: base( movementBehaviour )
	{}
}
public class ArtilleryUnit :
	CombatUnit
{
	public ArtilleryUnit(
		IMovementBehaviour
		 movementBehaviour )
		: base( movementBehaviour )
	{}
}
public class ArmouredUnit : CombatUnit
{
	public ArmouredUnit (
		IMovementBehaviour
		movementBehaviour )
		: base( movementBehaviour )
	{}
}
Notice how we have removed a number of the derived classes in this listing. Specifically, the specialisations of the InfantryUnit and ArtilleryUnit types have been dispensed with altogether, because the only reason for their existence was to enable us to override the Move() method.

The revised client code

Now, to create the different types of combat unit, we would write code similar to that shown below:
public List<CombatUnit>
	GenerateForces()
{
	List<CombatUnit> units =
		new List<CombatUnit>();
	// An airborne infantry unit
	units.Add( new InfantryUnit(
	new AirborneMovementBehaviour() ));
	// An armoured infantry unit
	units.Add( new InfantryUnit(
	new TrackedMovementBehaviour() ) );
	// A self-propelled artillery unit
	units.Add( new ArtilleryUnit(
	new TrackedMovementBehaviour() ) );
	return units;
}
If this style of construction code is making you nervous, feel free to apply the factory patterns that we covered in last month’s article.

Adding new movement behaviours

So what have we gained by using the Strategy pattern? Well, principally we’ve managed to reduce the code duplication, as all units that use a particular type of movement behaviour will share the same implementation code. This should help to make maintenance considerably easier; after all, you’ll only need to fix any bugs that you find with that behaviour in one place.

But that’s not all. It also allows you to add new movement behaviours very quickly. For example, you could add support for specialised mountain infantry simply by adding the following new class:

public class MountainMovementBehaviour
	: IMovementBehaviour
{
	public void Move()
	{ /* Skiing code goes here */ }
}
There’s another benefit that should be immediately obvious. As and when the MoD asks you to add other units to the mix, they can make use of the same movement behaviours as the combat units. That’s got to be good news!

Adding new types

The benefits go beyond just adding new movement behaviours, however. Using the Strategy pattern can actually make it much easier to add new types to the hierarchy. In order to convince ourselves of this, though, we’ll play through another moment in the scenario. You’ve coded up the application, sent the new prototype over to the customer and things are looking pretty good. Then your boss rushes in and says “Hi, we’ve just got a call from the customer. We need to be able to add Combat Engineers to the system. How long will that take?”

You do a bit of research and discover that combat engineers fight like infantry (but only at a pinch), but that they can also blow things up and build things. They also move like armoured or airborne units (engineers rarely walk; their equipment weighs too much). Naturally, you might be tempted to derive a new CombatEngineerUnit class from InfantryUnit, but this is flawed. After all, a combat engineering unit “is an” engineering unit that just happens to “fight like an” infantry unit.

So given how much we liked the results from our first go with the Strategy pattern, let’s take it a stage further and extract the fighting behaviours out from the CombatUnit type using exactly the same approach that we took with the movement behaviours, thereby yielding the code for the final version of the model:

public interface IFightingBehaviour
{
	void Fight();
	Symbol Symbol { get; }
}
public interface IMovementBehaviour
{
	void Move();
	Symbol Symbol { get; }
}
public class CombatUnit :
	IFightingBehaviour,
	IMovementBehaviour
{
	IFightingBehaviour
		fightingBehaviour;
	IMovementBehaviour
		movementBehaviour;
	public CombatUnit(
		IFightingBehaviour
		fightingBehaviour,
		IMovementBehaviour
		movementBehaviour )
	{
		this.fightingBehaviour =
			fightingBehaviour;
		this.movementBehaviour =
			movementBehaviour;
	}
	public virtual void Move()
	{
		movementBehaviour.Move();
	}
	public virtual void Fight()
	{
		fightingBehaviour.Fight();
	}
	Symbol IFightingBehaviour.Symbol
	{
		get { return
			fightingBehaviour.Symbol; }
	}
	Symbol IMovementBehaviour.Symbol
	{
		get { return
			movementBehaviour.Symbol; }
	}
	public void Display()
	{
		Symbol symbol =
			((IMovementBehaviour)
			this).Symbol;
		symbol.Add(
			((IFightingBehaviour)
			this).Symbol );
		symbol.Draw();
	}
	
	// other items elided for clarity
}
public class WalkMovementBehaviour :
	IMovementBehaviour
{ /* Implementation elided */ }
public class TrackedMovementBehaviour
	: IMovementBehaviour
{ /* Implementation elided */ }
public class AirborneMovementBehaviour
	: IMovementBehaviour
{ /* Implementation elided */ }
public class InfantryFightingBehaviour
	: IFightingBehaviour
{ /* Implementation elided */ }
public class ArmouredFightingBehaviour
	: IFightingBehaviour
{ /* Implementation elided */ }
public class
	ArtilleryFightingBehaviour :
	IFightingBehaviour
{ /* Implementation elided */ }
public class Symbol
{ /* Implementation elided */ }
Here we’ve taken the Fight() method and applied the Strategy pattern to it so that how combat units fight is provided by a concrete implementation of the IFightingBehaviour interface. You might also have noticed that we’ve exploited the fact that how a unit moves and fights (largely) drives what’s shown as its APP-6A symbol, so you’ll notice that the map symbol used in the Display() method is thus created using information from the two behaviours.

You might also have noticed that there are now no types derived from CombatUnit. We’ll examine what that means in just a moment, especially given that this refactoring has been performed in order for us to add a new combat engineering unit. For now, though, you can see that creating units merely becomes an exercise in combining appropriate behaviours:

public List<CombatUnit>
	GenerateForces()
{
	List<CombatUnit> units =
		new List<CombatUnit>();
	// An airborne infantry unit
	units.Add( new CombatUnit(
	new InfantryFightingBehaviour(),
new AirborneMovementBehaviour() ) );
	// An armoured infantry unit
	units.Add( new CombatUnit(
	new InfantryFightingBehaviour(),
	new TrackedMovementBehaviour() ) );
	// A self-propelled artillery unit
	units.Add( new CombatUnit(
	new ArtilleryFightingBehaviour(),
	new TrackedMovementBehaviour() ) );
	return units;
}

The CombatEngineerUnit defined

With the refactoring complete, it only takes a few moments to add this new unit type to the mix:
public class CombatEngineerUnit :
	CombatUnit
{
	public void BuildSomething()
	{ /* Code elided for clarity */ }
	public void BlowSomethingUp()
	{ /* Code elided for clarity */ }
	public CombatEngineer(
		IMovementBehaviour
		movementBehaviour )
		: base( new
		InfantryFightingBehaviour(),
		movementBehaviour )
	{}
	public override void Display()
	{
		// Add code to create the E in
		// the symbol here
	}
}
In this case, CombatEngineerUnit does indeed add some unique specialised behaviour: the BuildSomething() and BlowSomethingUp() methods. Since these are unique to combat engineers, it makes perfect sense to derive a specialisation from CombatUnit.

Reviewing and analysing the Strategy pattern

Let’s take a couple of moments to analyse the original design and the revamped design using the Strategy pattern. To kick off the discussion, Figure 2 shows the UML class diagram from the initial one, minus the actual members in each class.

Figure 2
Figure 2: The UML Class Diagram for Listing 2 (methods not shown)

As you can see, we initially took a very simplistic approach using inheritance to create the different types of combat unit. Intrinsically it looked like it met the model requirements, but from a practical perspective the movement code for the different unit types would have needed to be duplicated (i.e. armoured units, self-propelled artillery and mechanized infantry would all need identical code to move the simulated objects).

Attempting to add the combat engineering unit to this hierarchy would only have been possible by yet further duplication of both the infantry fighting code and the relevant movement code, or by introducing an artificial inheritance relationship between combat engineers and infantry.

Clearly, this would have made code maintenance untenable as the project grew.

So, we performed some refactoring, applied the Strategy pattern and thus came up with the new implementation. The UML class diagram (minus the Symbol class, which is not required for this discussion) for this code is shown in Figure 3.

Figure 3
Figure 3: The UML Class Diagram

At first glance, this diagram looks much more complicated, but that’s partly because of the fact that it shows CombatUnit both implementing the two interfaces and also having associations with the two interfaces via the movementBehaviour and fightingBehaviour fields. It also appears to be more complicated because we now have two inheritance (or rather, implementation) hierarchies for the different behaviours. And yes, it is undeniably more complex, and this is one of the consequences of using the Strategy pattern. Thus it only makes sense to adopt this pattern as and when it is forced upon us, or when the benefits outweigh the extra work. In our example, that situation arose when it became clear that many different combat unit types would need identical implementations for their movement and fighting behaviours.

“Has a” can be more powerful in problem solving than “is a”

What’s particularly interesting about the Strategy pattern is that it relies on applying knowledge that OO developers learn long before covering inheritance: the idea that an object is composed of other objects.

To be precise, we didn’t try to solve the problem purely in terms of traditional OO inheritance “is a” relationships. Instead, we used much more flexible “has a” relationships to separate the changeable behaviours from the underlying type.

Dynamically changing the behaviours

There’s another benefit to using the Strategy pattern: you can flex the behaviour of an object at run-time simply by replacing one type of behaviour with another. You simply cannot do this using inheritance alone – the object’s behaviour is fixed at compile time and can never change.

Let’s consider the example of our airborne infantry, which go through a number of different states, as shown in Figure 4.

Figure 4
Figure 4: The airborne infantry in action

As you can see, the airborne infantry significantly change their behaviours as they evolve through the three different states. To begin with, when moving by plane they have no fighting capability, but can move very quickly. Then they (bravely) leap from the aircraft and then when on the ground they fight and move like regular light infantry. We can actually model this in the simulation by exposing the behaviours as writable properties, as shown in this listing:

public class CombatUnit :
	IMovementBehaviour,
	FightingBehaviour
{
	private IMovementBehaviour
		movementBehaviour;
	public IMovementBehaviour
		MovementBehaviour
	{
		set
		{
			movementBehaviour = value;
		}
	}
	// repeat for fighting behaviour
	// all other items elided for
	// clarity
}

// In the client code
CombatUnit paras = new CombatUnit(
	new InfantryFightingBehaviour(),
	new AirborneMovementBehaviour() );
paras.Move();
// they fly to their destination and
// drop
paras.MovementBehaviour =
	new WalkMovementBehaviour();
This ability to dynamically change the behaviour for an object is very powerful. In fact, it’s so important that it’s described in another of the GoF’s design patterns: the State pattern. It can be hard to distinguish between the State and the Strategy patterns, as both of their UML class diagrams are identical (and thus would look like Figure 3), but the intent behind each of the patterns is very different.

The GoF succinctly summarise these two patterns in Design Patterns: Elements of reusable Object-oriented Software:

Strategy. Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from the clients that use it.

State. Allow an object to alter its behaviour when its internal state changes. The object will appear to change its class.”

(Note that I’ve added the emphasis in this quote.)

The Strategy pattern allows you to model closely related types through composition rather than inheritance; its intent is therefore to enable you to add new types without breaking or changing the existing type hierarchy, to reduce the amount of overriding that is required and to minimise code duplication.

The intent of the State pattern, on the other hand, is to provide a mechanism for an object to seemingly change its type independently of the client code, and without you having to write complex and hard-to-test conditional statements. One common and marked difference in usage is that with the Strategy pattern it is often the client code, or at least a factory object acting on behalf of the client, that specifies the behaviours, whereas with the State pattern the object will usually change its internal state (i.e. its behaviours) itself. What is clear, though, is that it’s using composition that enables both of these patterns to work and thus solve these relatively common programming problems.

Conclusion

In this article, we’ve examined a very important design pattern: Strategy. Its most potent feature is that it allows you to separate those aspects of an item that change away from the core type declaration, enabling you to often add new types to your application without breaking, or in certain cases changing, existing inheritance relationships. A commonly quoted OO design principle is that you should favour composition over inheritance. Hopefully, this article will have provided some justification for that principle.


David Wheeler is a freelance trainer and consultant, specialising in skills transfer to teams working with Microsoft .NET. He helps moderate Microsoft’s ASP.NET forums, is a regular speaker at Bearpark’s annual DevWeek conference, and will also be presenting sessions on how to use Design Patterns in Microsoft .NET at Software Architect 2007. He can be contacted at [email protected].

You might also like...

Comments

About the author

Dave Wheeler United Kingdom

Dave Wheeler is a freelance instructor and consultant who specialises in .NET application development. He’s a moderator on Microsoft’s ASP.NET and Silverlight forums and is a regular speaker at ...

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“It is practically impossible to teach good programming style to students that have had prior exposure to BASIC. As potential programmers, they are mentally mutilated beyond hope of regeneration.” - E. W. Dijkstra