It's been a while again, but it's time for another pattern. Today we'll look at the State Pattern.
First of all, the definition: "Allow an object to alter its behavior when its internal state changes. The object will appear to change its class."
An additional request has surfaced today, we need to keep track if a unit is alive or dead and let it respond differently based on the state it is in.
Initially we solved this by introducing a new enum called UnitState and adding lots of switch() statements to our code.
In the long run however, this would mean we have to keep on going into those statements whenever a new state needs to get added, which isn't exactly following the Open/Closed Principle we talked about.
Let's refactor this and introduce a new interface called IUnitState.
Instead of using an enum, we're going to introduce two new classes, which implement IUnitState to represent our different states.
By seperating the logic for different states in different classes, we can add a new state easily, by simply creating a new class, and we keep our code base structured.
For example, the most simple state looks like this:
When we pull all of this together we get the following class diagram, illustrating two concrete states and the state interface.
To the outside, whenever the internal state changes, it looks like the object, GameUnit, changed it's type because a different concrete state is providing an implementation for the actions.
When we test this code, we can see the behaviour of internal state changing after the first Kill() command.
I realize this isn't the best example given to illustrate the State Pattern, I'm not quite that happy with it, stretching the game example like that, sometimes it works out, sometimes it feels a little forced, like today. I hope it made sense, be sure to check out the sites below for some other examples as well.
I've uploaded the solution again so you can have a look.
Some additional information on the State Pattern:
Greetings fellow David - just wanted to let you know how much I appreciate this series!
- David McClelland (from Houston, TX)
David,
State are finite. May be introducing Enum to implement your concrete state implementations. This would give a tier relation between your state implementation.
--danny
Hi David.
I have a different implementation for a state machine where each method returns a new type instead of setting up a _state variable. Implemented like that the code you posted would be something like:
soldier = new ISoldier(); //An interface for every kind of Soldier States you'd like to have.
soldier = soldier.Kill();
soldier = soldier.PerformShoot();
Even tho I can't see possible problems with this implementation, I'm not sure if they aren't hidden somewhere.
Do you think that this implementation is plausible?