Is the State pattern broken?
I've been looking at the state pattern today, with the goal of allowing business entities to behave differently depending on their state. So, an Order in "Shipped" state would have a completely different behavior to an order in "Placed" state; I might not be able to update an order in Shipped state, but I could if it were merely "Placed".

In Design Patterns [GOF], the intent of State is this:
Allow an object to alter its behaviour when its internal state changes. The object will appear to change class
Perfect. But, when I had a crack at implementing it, I got a bit peeved. Here's a few reasons why:
Too many classes; An order entity with states Draft, Raised, Packed, Shipped and InQuery would require 7 classes: One for the context, one for state base class, and one each for the states themselves. This doesn't feel right to me.
Violation of DRY? I'm repeating the interface declarations several times over. If I weren't using this pattern, I'd have only 1 class. I'm just not sure that, in my simple cases at least, the extra conceptual baggage is worth it.
Lack of cohesion. The context is delegating to the various states, and in turn each of those states contains business rules. Would it be better to keep all business logic in one place, or is State an elegant variation of the "rule object" pattern and in fact more cohesive?
Lack of real-world use. I don't see the State pattern used that much, certainly nowhere near as much as Singleton, Strategy, Factory, Iterator, Mediator, Observer and many others. I tried a brief .NET Reflector search, but couldn't find one use of this pattern in the .NET framework. A google code search came up with more possible uses.
Before I get slammed for this post, I am smart enough to see some good things about the State pattern:
- I like the fact that it uses composition over inheritance to handle state-specific behaviour.
- I like the fact that the pattern makes states a first class citizen, that's explicit.
- I also like the fact that individual states are testable.
- There's a hint of OCP here, you can add more states (extend the class) without modifying it.
I must admit, I'm not really qualified to GOF bash :) And, I haven't got the experience with this pattern to truly say I don't like it. However, I would like to find a way of implementing the state pattern in c# so that:
- Entities can only transition to allowable states
- You can have different behaviors in each state
- You don't need to create lots of classes
- You can keep business rules in one place Entity
- It feels natural!
Any thoughts?
Comments
-
Also,
The State Design Pattern compromises the encapsulation of the context class, which typically requires granting friendship to all State classes.
It enforces indirect access to the context’s parameters from the methods of the concrete state subclasses (via the context pointer).
It isn’t hierarchical. That is, it can’t be used to directly implement statecharts.
The book Practical Statecharts in C/C++ has the best statechart implementation I’ve ever seen. There’s a second edition coming out next month, but the original is still a classic in my opinion. Porting to C# should be very easy, if it hasn’t already been done. I know it’s been ported to Java and ActionScript.
-
Interesting observations, Tad. I’d not thought of those.
I think I get the hierarchial issue. I worked on some UML CASE tool extensions once and used a graph library to build an internal representation (ie. model) of the state machines diagrams. It seemed to fit well. We could then use graph constructs to do things like find the shortest path to a given edge. The traditional state pattern may not make such things possible.
Thanks for the book recommendation, will check it out!
-
The GOF patterns where designed/created in different times when different tools etc.. where available for developers. So it is very well possible that in C# an problem can be resolved much cleaner, easier and nicer then GOF describes in their pattern as their solution.
-
Seems like a good point JV. I think the intent of the patterns are almost timeless, but implementations are more likely to vary in acceptability and popularity over time.
GOF was written in the 80’s I think, it’s remarkable that it still hits home on every read despite the endless evolution of CS over the last 20 years.
-
You shouldn’t be scared by “too many classes”. I would prefer that to a single, bloated class. Ideally, each class should have one purpose, and one public method. It makes code easier to read and maintain. But, nothing is absolute. If there is nothing to these classes other than to exist as a description—then it would certainly be simpler to declare them as public static final members of some common object.