Saturday, March 27, 2010

Don’t Give Up on the State Pattern Just Yet - Revisited

In my previous post on the subject, I showed how you can remove some of the friction caused by applying the State pattern. In fact, as some of you rightfully pointed out, this friction isn’t caused by the State pattern itself but by a violation of the Interface Segregation Principle.   The use of role interfaces somewhat mitigated this violation but caused some type checking and casting in the context class (named Account in our example).

I just wanted to put out a slight variation of our solution that defers this kind of type checking until runtime. In other words, we’re going to apply some duck typing in order to come up with some improvements.

But hang on, isn’t C# supposed to be a static language and isn’t duck typing an exclusive feature of dynamic languages like Ruby or Python? Heck no! One can have duck typing in a static language as well. A good example of this is the Boo programming language which is a static language but provides the ability to give up this safety net. But I do believe that dynamic languages like Ruby or Python provide a more supple syntax for supplying duck typing capabilities while a static language usually requires a bit more ceremony.

The latest C# 4.0 compiler delivers some dynamic language features using the dynamic keyword which in turn accomplishes it’s functionality by leveraging the DynamicObject class (which seems to live in the System.Dynamic namespace). I have to admit that I didn’t spent much time on this yet.

But while the rest of the world is still on .NET 3.5 or earlier versions of the .NET framework, we don’t have to wait until the next upgrade to use some of the dynamic language features like duck typing, mixins and the like.

Let me first show you the code of the Account class from the previous post that demonstrates the type checking and casting to a role interface: 

public void Withdraw(double amount)
{
    // One can not always withdraw
    if(false == CanWithdraw())
    {
        // Should throw an exception or at least a towel
        Console.WriteLine("No funds available for withdrawal!");
        return;
    }

    var canWithdraw = (ICanWithdraw)State;
    canWithdraw.Withdraw(amount);

    ...
}

private Boolean CanWithdraw()
{
    return State is ICanWithdraw;
}

What I would like to do is to remove the CanWithdraw check entirely without running into a NullReferenceException when a particular state doesn’t support withdrawing money. But first, I want to slightly decouple the Account class from the SilverState, GoldState and RedState classes by introducing an interface named IAccountStateChanger.

public interface IAccountStateChanger
{
    void InstituteStateTo(State newState);    
}

This is now used by the state classes to change the state of the Account class without using a property setter in order to get rid of the false sense of encapsulation. The implementation of this interface by the Account class is where the fun begins.

void IAccountStateChanger.InstituteStateTo(State newState)
{
    _state = newState;
    _dynamicState = new DynamicObject(_state) + _missingStateMethodHandler;
}

Besides having a state we also introduced a dynamic state which is simply an instance of Linfu’s DynamicObject class. I’ll talk about the missing state method handler part shortly, but first let’s look what we can do with our dynamic state object.

public void Withdraw(Double amount)
{
    var canWithdraw = _dynamicState.CreateDuck<ICanWithdraw>();
    canWithdraw.Withdraw(amount);
    
    ...
}

Notice that we got rid of the type checking part. But what if a particular state doesn’t support withdrawing money? Here’s were the method missing piece of the puzzle falls in. Linfu provides an interface named IMethodMissingCallback which lets you decide what to do when the requested method call cannot be resolved.

public class MissingStateMethodHandler : IMethodMissingCallback
{
    public void MethodMissing(Object source, MethodMissingParameters missingParameters)
    {
        if(typeof(ICanWithdraw).GetMethods()[0].Name == missingParameters.MethodName)
        {
            Console.WriteLine("No funds available for withdrawal!");
        
            // Let Linfu know we're on top of things        
            missingParameters.Handled = true;
        }
    }

    public Boolean CanHandle(MethodInfo method)
    {
        return false;
    }
}

You can do pretty much anything in here like delegating the call to another method, but for demonstration purposes we just write a message to console. As shown earlier we literally add an instance of this handler to the dynamic object and we’re all set up. Using this approach yields the same results but without the type checking.

I’d like to mention that I’ve been using the DynamicObject class from Linfu 1.0 which you can download here. For some reason this class hasn’t been included in the 2.0 release and higher which is a bit sad because I really like some of the possibilities it has to offer. I’ll cover some of these in one of my next posts.

Saturday, March 20, 2010

Don’t Give Up on the State Pattern Just Yet

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:

public interface ICanDeposit
{
    void Deposit(Double amount);
}

public interface ICanWithdraw
{
    void Withdraw(Double amount);
}

public interface ICanPayInterest
{
    void PayInterest();   
}

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.

class RedState : State, ICanDeposit
{
    private const Double UpperLimit = 0.0;

    public RedState(State state)
    {
        Balance = state.Balance;
        Account = state.Account;
    }

    public void Deposit(double amount)
    {
        Balance += amount;
        StateChangeCheck();
    }

    private void StateChangeCheck()
    {
        if(Balance > UpperLimit)
            Account.State = new SilverState(this);
    }
}

The RedState therefore only implements the ICanDeposit interface. Just for the record, the code of the State base class is now dramatically reduced.

abstract class State
{   
    public Account Account { get; protected set; }
    public Double Balance { get; protected set; }
}

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 void Withdraw(double amount)
{
    // One can not always withdraw
    if(false == CanWithdraw())
    {
        // Should throw an exception or at least a towel
        Console.WriteLine("No funds available for withdrawal!");
        return;
    }

    var canWithdraw = (ICanWithdraw)State;
    canWithdraw.Withdraw(amount);
    
    ...
}

private Boolean CanWithdraw()
{
    return State is ICanWithdraw;
}

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.