Design Patterns - Strategy Pattern
The first pattern I want to talk about is the Strategy pattern, which always reminds me about the Command & Conquer games so I'll simply use it as an example :)
First of all, the definition: "Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it."
I'm bad at remembering definitions or trying to imagine what they really mean, so let's just go ahead and try to create something and learn as we go, eventually we'll end up implementing the Strategy pattern and you'll 'get it' for the rest of your life, without a definition.
A long time ago, we made a simple strategy game, having only 2 units, a soldier and a tank, both were able to shoot at each other which we implemented as follows:
The Shoot() logic is contained in the base GameUnit class, since it's identical for both units. Each unit takes care of drawing itself.
After a while, we receive a request to add in an Engineer, which is a unit used to take over buildings and more importantly, he can't shoot.
If we just added an Engineer class similar to the Soldier one, he would be able to shoot as well, which we don't want. We could for this once just override the Shoot() method for the Engineer and make it empty.
Can you already see where this is going to end up? Maintenance Nightmare!
Eventually we end up with lots of useless code being repeated for every class which has a different shooting logic, where you have to open up every class to figure out all the available implementations. Let's not implement it like this!
What if we were to get rid of the Shoot() logic in the GameUnit class and make an IShootable interface for the units that can actually shoot?
That looks a bit cleaner, but wait! We simply shifted the nightmare, because now the Soldier and Tank have identically the same code in their Shoot() method. This isn't the solution either, let's take a look at what our higher level goal actually is.
We can see the part that changes is how a unit shoots. If we take a closer look at shooting and implementing future classes, it is very possible we'll end up with a class that has a very different shooting algorithm or has upgradeable parts, changing the way it shoots. You could say the way a unit shoots is a behaviour of a unit.
Remember the definition of the Strategy pattern? The shooting behaviour we have just defined is actually an algorithm, while the requirement of units being able to get upgraded implies the behaviours have to be changed at run time, making them interchangeable.
Making things interchangeable usually means having less things hard-coded in your application, which reminds of a great saying: Program to an 'interface', not an 'implementation'.
Let's separate all our shooting logic from our units and create a totally new set of classes defining all possible shooting behaviours.
Now it's only a matter of letting our GameUnit use these behaviours. We'll do this by programming against the IShootingBehaviour interface instead of against an implementation. This way we can dynamically replace the behaviour at run time, and have a very flexible programming model towards the future.
Adding a new way of shooting is simply a matter of adding a new class implementing the IShootingBehaviour interface after which all our units could use it.
And that's it! We've implemented the Strategy pattern. We defined a family of algorithms (IShootingBehaviour), we encapsulated each one (NormalShot, CantShoot, ThrowKnifes) and made them interchangeable (ShootingBehaviour property).
Each client can define his algorithm as we currently did in the constructor, by setting the property to the desired implementation. In a future pattern we'll see how to set this different, since it's not that pretty doing it in the constructor.
Note that even though we are setting a shooting implementation via the constructor, it is possible to change the way a unit shoots at runtime by setting the ShootingBehaviour property.
I've uploaded the sample project I have used while learning this pattern so you can have a look at the code representing the above diagrams yourself.
Some additional information on the Strategy pattern: