Last week, Greg Young wrote a blog post about State Pattern Misuse. In this post he talks about how ugly the State pattern can become if some operations are not allowed when the context object is in a particular state. The solution he proposes is to use a separate domain class for each state in the model so that it contributes to the Ubiquitous Language.
Just to be clear, I agree and value this approach when it makes sense in the domain model. However, I do not like to entirely give up on the use of the State pattern either. We can eliminate some of the friction by using a very simple approach, namely role interfaces.
To show you a simple example, I took the code of one of the samples on the DoFactory web site and put in some refactoring. Please take a look at the original code before reading any further.
Now instead of having abstract methods on the State base class, I created three separate role interfaces:
Both the SilverState and the GoldState class implement all these interfaces, but the one we’re particularly interested in is the RedState class because only deposits should be allowed for this state.
The RedState therefore only implements the ICanDeposit interface. Just for the record, the code of the State base class is now dramatically reduced.
With this setup we can use these role interfaces in the Account class to determine whether a particular operation is allowed for the current state.
public interface ICanDeposit
{
void Deposit(Double amount);
}
public interface ICanWithdraw
{
void Withdraw(Double amount);
}
public interface ICanPayInterest
{
void PayInterest();
}
This way we’re able to eliminate all operations that don’t make sense for a particular state while still being able to determine all of its capabilities when needed.
Hope this helps.