How to use state pattern correctly?

@Ivan: There are a number of resources available on the web for Hierarchical State Machines (HSM). Miro Samek has written extensively about this design pattern and offers a lot of helpful information.

Some articles that should be of interest:

  • State-Oriented Programming (SOP) (Samek) (pdf)
  • Hierarchical State Machines - a Fundamentally Important Way of Design (Samek) (pdf)
  • Practical State Charts in C/C++ (Samek) (link to google-books)
  • State-Oriented Programming (by Asher Sterkin) (pdf)

The big benefit of using HSM over flat FSM state charts described by Mealy and Moore is that the hierarchy creates a separation of responsibility. Sub-states only need to handle those conditions that they are expressly designed to handle--unhandled events get passed up to the parent state, if the parent state isn't expressly designed to handle it then it is passed up to the next-higher parent and so on. It allows you to create small, manageable state machines that each serve a single purpose--one that can fit within a single object. As new features are added, or as new classes are added, they only need to handle their own little part of the world and pass on the unhandled events to their respective parents.

When implemented correctly, you get a robust program with low cyclomatic complexity, that is easy to modify or upgrade as needed.


As you probably have read, the State Design Pattern is useful when state varies the behavior of some object whose composition includes that state. This implies the idea of a State abstract class, interface, or enumerated type - albeit depending on the language Duck Typing will do as well - that defines any common behavior and/or required methods.

Key Aspects

There are really two key aspects to consider in working with the state pattern: enumeration and transition. Enumeration simply means identifying the set of possible states (e.g. days of the week), or more abstractly the types of states (i.e. meta states) such as starting, ending, and in between for a workflow engine.Transition means deciding how to model movement between states where this is typically either done by capturing all possible transitions in a tabular representation (i.e. Finite State Machine) or make each state know its possible "transitions" to other states.

Typically transitions go hand in hand with meta states because its not possible to know all states and relationships ahead of time in such a dynamic system where new states, and thus transitions, can be added at runtime. In addition, with the transition approach, certain behavior - notifications for instance - becomes part of the transition, instead of the state itself.

Examples

There are several scenarios I've either worked on or discussed where this is a use facility:

  1. Workflow
  2. Computer Game Opponent A.I.
  3. Process Orchestration

By workflow I mean something like jBPM. Systems like this are concerned with commanding the right attention, of the right people, at the right time. They usually send lots of emails or some other sort of notification. And, the process they represent needs the ability to change as the organization changes, whereas the data being managed typically changes much more slowly.

Computer Game Opponent A.I. is self explanatory. Not something I've written, but in conversation with those who have, these systems are usually self contained. In other words, unlike workflow, the game usually doesn't have the facility to alter the process used to control computer opponents.

Process Orchestration is similar to workflow, but focused on system integration, instead of people interaction. The Apache Mule framework is an example. Here state can describe status (e.g. started, in process, ended) and type (e.g. ftp integration point, sql integration point).

Conclusion

Unlike other answers, I think state encapsulation is an excellent way to manage change in software systems. Done well, it facilitates those changes or enables users to do so at runtime. You make a tradeoff of more flexibility in exchange for increased implementation complexity. So such an approach is probably not useful for shopping cart for instance, where the behavior is probably very well known and not like to change. On the other hand when the process is subject to change, it makes a very good fit.


Just my 2 cents, the state pattern always turns to be hard to maintain as it is hard to understand by those who has not coded it. I usually fallback to old standard array of function/method pointers, as I've in my old C experience. You just build a two dimensions array of function pointers with state/signal for lines/columns. Easier to understand. you have a class that manage that and you delegate to other class to handle complexity ...

my2c


Most of the times, the states in a state pattern design are handling more that one state (or substates of the state) which makes them harder to maintain.

If a state has any kind of selection in there, its mostly handling more than one state.

I takes a lot of discipline to keep the states clean.

A possible solution to this is to make more complex states statemachines themselves (HSM). This makes it a lot more readable at the upper level because it has to deal with fewer states.