Jeremy D. Miller -- The Shade Tree Developer

Sponsors

The Lounge

Wicked Cool Jobs

Syndication

News

Advertisement

Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
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.

Posted Sun, Apr 30 2006 1:58 PM by Jeremy D. Miller
Filed under:

[Advertisement]

Comments

Ayende Rahien wrote re: The State Pattern: An Underappreciated Pattern
on Sun, Apr 30 2006 3:49 PM
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?)
Jeremy D. Miller wrote re: The State Pattern: An Underappreciated Pattern
on Sun, Apr 30 2006 6:20 PM
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
Eber Irigoyen wrote re: The State Pattern: An Underappreciated Pattern
on Sun, Apr 30 2006 11:46 PM
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)
Brian wrote re: The State Pattern: An Underappreciated Pattern
on Mon, May 1 2006 12:56 PM
Eber: Try using an RSS reader, like google.com/reader you can then pull all your content into one place...
Kevin Miller wrote re: The State Pattern: An Underappreciated Pattern
on Mon, May 1 2006 1:36 PM
Excellent blog posts that I really wish I could more easily read. Please please fix this.
Eber Irigoyen wrote re: The State Pattern: An Underappreciated Pattern
on Tue, May 2 2006 1:25 AM
...on my reader it doesn't look too wide... i just has double spacing in all the source code =o|
Kevin Miller wrote re: The State Pattern: An Underappreciated Pattern
on Tue, May 2 2006 4:39 PM
Oh yeah? On my 20" wide screen monitor it just barely fits. My point is not all people use RSS readers.
Michael wrote re: The State Pattern: An Underappreciated Pattern
on Wed, May 3 2006 12:44 PM
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
Darrell Norton wrote re: The State Pattern: An Underappreciated Pattern
on Wed, May 3 2006 2:58 PM
Why can't you change strategy at runtime?  Both state and strategy are dynamic, as far as I know.
John Wood wrote Hidden Complexity in OOP Code
on Thu, May 11 2006 10:16 PM
Cyclomatic Complexity measures the number of linear paths through a program. It claims that the more...
Gendo wrote re: The State Pattern: An Underappreciated Pattern
on Fri, Aug 4 2006 5:52 PM
Looks fine to me, and I'm using FF 2.0b on XP.

Regards.

ps. great lectures btw, keep them coming :)
Jeremy D. Miller -- The Shade Tree Developer wrote Best of the Shade Tree Developer (with actual links!)
on Mon, Aug 7 2006 4:51 PM
Between being extremely short handed at work, tech' reviewing a new book, a
possible book proposal...
Jeremy D. Miller -- The Shade Tree Developer wrote Best of the Shade Tree Developer (with actual links!)
on Fri, Sep 1 2006 2:33 PM

Between being extremely short handed at work, tech' reviewing a new book, a possible book proposal

Anders Norås' Blog wrote DSL Tools: A Complex Solution for a Simple Problem
on Wed, Jul 25 2007 9:43 AM

Last night I was unable to sleep, so I started reading Domain Specific Development with Visual Studio

Effective Java, even c# (3) Classes and Interfaces « Iron9light’s Tech Weblog wrote Effective Java, even c# (3) Classes and Interfaces « Iron9light’s Tech Weblog
on Thu, Jul 31 2008 5:40 AM

Pingback from  Effective Java, even c# (3) Classes and Interfaces « Iron9light’s Tech Weblog

James Taylor wrote re: The State Pattern: An Underappreciated Pattern
on Fri, Feb 27 2009 8:11 AM

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.

niceboomer wrote re: The State Pattern: An Underappreciated Pattern
on Tue, Mar 24 2009 9:00 PM

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 ^^

Nicholas Blumhardt wrote State Machines in Domain Models
on Sat, Apr 18 2009 12:48 PM

I was reminded today of Stateless , a little project that I’m quite fond of. Stateless is a hierarchical

Add a Comment

(required)  
(optional)
(required)  
Remember Me?
Devlicio.us