The State Pattern: An Underappreciated Pattern

Following up on my post on Six Design Patterns to Start With, I mentioned the State pattern in regards to its similarity to the Strategy pattern.  It might not come up that often, but it’s very effective in creating cleaner code in certain situations.

From www.dofactory.com, the State pattern is

Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.

Many objects need to behave differently in several ways when some sort of internal state changes.  The State pattern isolates the divergent functionality into swappable classes implementing a common interface.  The main object simply delegates to its internal state object at the appropriate times.  When the “state” property of the main object changes, it simply has to replace its internal state member with a different object. 

Let’s jump into an example.  For the last three years or so I’ve been using a data access layer framework I’ve written (and rewritten) to do very basic data access.  The Facade for the data access layer is called DataSession.  Among other things, DataSession wraps and manages all access to the underlying ADO.Net connection and transaction objects.  What I came up with was a design that allowed consumers of a DataSession to just drop off an IDbCommand for execution not have to worry about transaction boundaries or IDbTransaction objects.  The public interface of IDataSession looks like this:

    [PluginFamily("Default")]
    public interface IDataSession
    {
        bool IsInTransaction { get; }
 
        void BeginTransaction();
        void CommitTransaction();
        void RollbackTransaction();
 
        int ExecuteCommand(IDbCommand command);
        int ExecuteSql(string sql);
        IDataReader ExecuteReader(IDbCommand command);
        IDataReader ExecuteReader(string sql);
        DataSet ExecuteDataSet(IDbCommand command);
        object ExecuteScalar(IDbCommand command);
 
        ICommandCollection Commands { get; }
        IReaderSourceCollection ReaderSources { get; }
 
        void Initialize(IInitializable initializable);
    }

Internally, the ADO.Net object usage varies a little bit between an “autocommit” mode where each command is its own transaction and a full blown transactional mode.  We could write if/then logic inside each method in DataSession to check if it is in a transactional state, but that will make each method longer, messier, and create some duplication.  This is where the State pattern comes in to play with an interface called IExecutionState.

    public interface IExecutionState
    {
        int Execute(IDbCommand command);
        IDataReader ExecuteReader(IDbCommand command);
        DataSet ExecuteDataSet(IDbCommand command);
        object ExecuteScalar(IDbCommand command);
    }

DataSession has a private field called _currentState that holds an IExecutionState object.  Take a look at this method in DataSession:

        public int ExecuteCommand(IDbCommand command)
        {
            try
            {
                return _currentState.Execute(command);
            }
            catch (Exception ex)
            {

// Just wraps the ADO exception with a full
// description of the IDbCommand that failed,
// including parameter values
               throw new CommandFailureException(command, ex);  
            }
        }

All it does is delegate to the active State object and provide some consistent exception handling.  So, how does the State object get set?  First off, the DataSession starts with an AutoCommitExecutionState object in the _currentState field.  The state object is replaced when a transaction is started.

        public void BeginTransaction()
        {
            if (IsInTransaction)
            {
                throw new ApplicationException("A transaction is already started!");
            }
 
            _transactionalState.BeginTransaction();
 
            // Replace the _currentState with the transactional state
            _currentState = _transactionalState;
        }

Then return to the “autocommit” state whenever the transaction is committed or rolled back.

        public void CommitTransaction()
        {
            if (!IsInTransaction)
            {
                throw new ApplicationException("A transaction is not started!");
            }
 
            _transactionalState.CommitTransaction();
 
            // Replace the _currentState with the default "Auto Commit" state
            _currentState = _defaultState;
        }

What did the usage of the State pattern here accomplish?  From my perspective it eliminated a lot of if/then logic and greatly simplified the DataSession class.  It also isolated the transactional code in a single spot where it became easier to find later, and that’s awfully important. 

Some Other Examples

Occasionally connected Smart Clients are a hot topic the past couple years.  At several points the smart client has to behave differently based on whether or not its connected to its backend or running locally.  I’ve never done this, but I bet this would be a perfect opportunity to use a State pattern.

I’ve used the State pattern effectively with user interface screens.  Say you have a screen that enables users to edit some sort of business entity.  The screen will probably need to behave differently based on whether or not the entity is being created, viewed, or edited.  On a project a couple years ago we were able to reuse the same screen to perform several different actions by making the screen controller class delegate to an internal State object for certain operations within the normal screen flow.  It enabled us to collapse a couple screens down to one and allowed us to add additional actions to the screen with less effort.  This might be relevant to my current project.  We are building a little application to manage a simple workflow of a new type of business entity with a couple different steps.  We might be able to utilize a state pattern that enables or disables screen actions based on the current state of the business entity and the type of user using the screen.

Advantages of the State Pattern

  1. Kill off if/then statements.  This is one of the primary goals of many of the original Gang of Four patterns, and it’s a worthy goal.  If/then branching can breed bugs.
  2. Reduces duplication by eliminating repeated if/then or switch statements, same as its close cousin the Strategy pattern.
  3. Increased cohesion.  By aggregating state specific behavior into State classes with intention revealing names it’s easier to find that specific logic, and it’s all in one place.
  4. Potential extensibility.  Going back to DataSession, I might want to add some sort of asynchronous or delayed caching mode to DataSession.  I could do that by implementing a new version of the IExecutionState interface.
  5. Better testability.  We could have solved the DataSession state problem by using inheritance and creating separate AutoCommitDataSession and TransactionalDataSession classes, but the old “favor composition over inheritance” rule in OO design says that’s not the best idea and I agree.  I was able to unit test the inner workings of DataSession effectively by using mock objects to test the interaction between DataSession and its IExecutionState object without touching a database.

About Jeremy Miller

Jeremy is the Chief Software Architect at Dovetail Software, the coolest ISV in Austin. Jeremy began his IT career writing "Shadow IT" applications to automate his engineering documentation, then wandered into software development because it looked like more fun. Jeremy is the author of the open source StructureMap tool for Dependency Injection with .Net, StoryTeller for supercharged acceptance testing in .Net, and one of the principal developers behind FubuMVC. Jeremy's thoughts on all things software can be found at The Shade Tree Developer at http://codebetter.com/jeremymiller.
This entry was posted in Design Patterns. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • anon

    I’m a little confused by the sudden appearance of “_transactionalState” in the example. Can you explain this one?

  • Nilesh Gule

    Nice post. I also posted about another example of State pattern using Loan states as an example. 
    http://www.nileshgule.com/2012/07/state-design-pattern.html 

  • niceboomer

    Thanks a lot 4 the great article.

    I am sorry but I’m still not very clear about the state pattern in your IDataSession example.

    Will you create 2 concrete classes implementing IExecutionState to avoid if clause in the origin example? If so, these 2 classes have almost logic the same except the Connection.Close statement, haven’t it? Some sort of duplicated code?

    And second, you wrote, “First off, the DataSession starts with an AutoCommitExecutionState object in the _currentState field.” in the article. But I wonder will I have to hard code the initialization of AutoCommitExecutionState in my DataSession object? or will I create it via IoC container?

    I am very appreciate your answer ^^

  • James Taylor

    I thought the difference between Strategy is which class is responsible for changing implementation.

    In Strategy, one can change the strategy/implementation class externally.

    In State, the current State instance decides on the next State and is responsible for setting it.

  • Gendo

    Looks fine to me, and I’m using FF 2.0b on XP.

    Regards.

    ps. great lectures btw, keep them coming :)

  • http://codebetter.com/blogs/darrell.norton/ darrell

    Why can’t you change strategy at runtime? Both state and strategy are dynamic, as far as I know.

  • Michael

    IE on Windows…. Firefox on Windows and Linux…. Tiny window and fully maximized at high-res…. Looks perfect.

    As usual, it’s luser error.

    Michael

  • http://scoundrel@gmail.com Kevin Miller

    Oh yeah? On my 20″ wide screen monitor it just barely fits. My point is not all people use RSS readers.

  • http://ebersys.blogspot.com/ Eber Irigoyen

    …on my reader it doesn’t look too wide… i just has double spacing in all the source code =o|

  • Kevin Miller

    Excellent blog posts that I really wish I could more easily read. Please please fix this.

  • Brian

    Eber: Try using an RSS reader, like google.com/reader you can then pull all your content into one place…

  • http://ebersys.blogspot.com/ Eber Irigoyen

    I’m liking these articles, but this is so hard to read, and this is not a FireFox or IE, it looks bad in both… and even in Opera (too wide, I hope I’m not alone on this)

  • jmiller

    Ayende,

    That sounds like a good definition to me. I’ve seen a lot of people, and I agree, that the State pattern may just be a specialized case of Strategy. Either way, it’s the same intention to move variation into polymorphism.

    Jeremy

  • http://Ayende@ayende.com Ayende Rahien

    I was never able to differenciate between State and Strategy, what is the different between them, that a strategy doesn’t change on runtime (only in object construction?)