{ by david linsin }

April 06, 2009

The State Pattern

A couple of weeks ago I had to come up with a design for a state machine at work. Even though a colleague mentioned the State Pattern, I thought it was oversized and being the pragmatic programmer I am, I decided to take the easy turn.

I've never really used the State Pattern before and I have to admit, even after glancing at the UML diagram, I couldn't quite figure out how this is gonna help me solve my problem. In case you are like me and need a little recap on the State Pattern, let's look at the wikipedia summary:

The state pattern is a behavioral software design pattern, also known as the objects for states pattern. This pattern is used in computer programming to represent the state of an object. This is a clean way for an object to partially change its type at runtime.
from wikipedia


Starting from this description, it seemed like there is a hammer, which looks for a nail. Having a concrete state class for each state in my design? I'm going to end up with a truckload full of classes and they all need to be carefully designed and tested.

With this mindset, I went down the switch/case-if/else road and designed the state machine in the most straight forward, but most unmaintainable way possible. Here's an imperative style code sample, which points out how not to implement a state machine:
public void insertCoins() {
if (state == NO_COINS && numberOfCoins >= MIN_COINS) {
state = COINS_OK;
} else if (state == NO_COINS && numberOfCoins < MIN_COINS) {
state = NO_COINS;
System.out.println("more coins!");
} else if (state == SOLD_OUT) {
state = RETURN_COINS;
}
}
// more transitions like dispenseFood(), printReceipt() and soldOut()

If you are like me and have never used the State Pattern, you probably think "What is wrong with this code?". The answer is nothing! It's just very imperative and highly unmaintainable. Imagine if you have to add a new state, you will need to adopt every if/else blocks in each transition method. In addition to that, you need to update each test case you wrote.

After reading on the State Pattern in Head First Design Patterns, which explains it very visually, I would change my code above into something like this:
public class NoCoins implements State {
public void insertCoins() {
if (numberOfCoins >= MIN_COINS) {
context.setCoinsOk();
} else {
System.out.println("more coins!");
}
}
// more methods defined in State, like dispenseFood()...
}

public class SoldOut implements State {
public void insertCoins() {
context.returnCoins();
}
// more methods defined in State, like dispenseFood()...
}

Each state gets a concrete class and common functionality can be aggregated in an abstract super class (I used an interface here instead). The member context is the representation of the state machine, which is used by the client to transition between states.

The main advantages of the State Pattern, according to Head First Design Patterns, are:

  • unlike a procedural state machine, it represents state as a full-blown class
  • the context object gets its behavior by delegating to the current state object
  • it allows a context to change its behavior as the state of the context changes

  • My state machine implementation was pretty simple, so I couldn't see any downside using the imperative approach. However, trying to test the beast ended up to be much more complicated than the implementation itself. A colleague pointed out the design smell (thanks Alexander).

    With the State Pattern, each state is represented by a class, it can be tested in isolation. I think that is one of the most compelling advantages. It outweighs the argument, that you have much more classes than with an imperative approach.

    I really enjoyed reading up on the State Pattern in Head First Design Patterns. Each comes with a visually rich example, giving you everything, needed to use it in your code. It even compares a procedural/imparative implementation of a state machine with the much more improved version using the State Pattern. I find that one of the most effective ways to learn.

    6 comments:

    Justin said...

    Hey just read over your article while looking at the state pattern myself. It was nice to read about someone who has actually used this pattern and tried the alternate. People underestimate how much of a PITA it can be to maintain those monstrous switch statements. Class explosion would only happen if you have an extremely large state machine and then could you imagine that switch of if/else block ;)

    Ollie said...

    Yet another great one! If the scope of your state implementations is managable (meaning you only have 3 or 4) you can easy build an Enum based implementation of your State interface that could make things more concise in certain cases.

    Josh Bloch presented this way of implementing states in his "Effective Java"

    Regards,
    Ollie

    curious said...

    What makes this better than e.g. SCXML ?

    curious said...

    SCXML:

    http://commons.apache.org/scxml/

    http://www.w3.org/TR/scxml/

    david said...

    Frankly, I haven't heard of SCXML before. In their wiki it's described as follows:

    ...State Chart XML (SCXML), which is a general-purpose event-based state machine language that can be used in many ways...

    I think SCXML is a whole different approach, similiar to JBoss Rules, as the State Pattern described here. It looks like SCXML is a special purpose language designed to implement state machine. If your requirement states, that you need a standardized solution, which must be easily adaptable and customizable than SCXML might be something to look at.

    As I said I haven't heard of it before, but to me it looks a lot like there's a hammer which looks for a nail.

    Janusz said...

    For large state machines it may be a lot easier to build a model and use State Machine Generator.
    You may chack SM Gallery at www.StateSoft.org


    com_channels

    • mail(dlinsin@gmail.com)
    • jabber(dlinsin@gmail.com)
    • skype(dlinsin)

    recent_postings

    loading...