Applied Design Patterns with Java

Behavioral :: State (305) {C ch 23}

Implementation

The following implementation issues are relevant to the State pattern:

  1. Who defines the state transitions? The State pattern does not specify which participant defines the criteria for state transitions. If the criteria are fixed, then they can be implemented entirely in the Context. It is generally more flexible and appropriate to let the State subclasses specify their own successor state and when to make the transition. This requires adding an interface to the Context that lets State objects set the Context's current state explicitly.
    Decentralizing the transition logic in this way makes it easy to modify or extend the logic by defining new
    State subclasses. A disadvantage of decentralization is that one State subclass will have knowledge of at least one other, which introduces implementation dependencies between subclasses.
  2. A table-based alternative. Some have advocated another way to impose structure on state-driven code: using tables to map inputs to state transitions. For each state, a table maps every possible input to a succeeding state. In effect, this approach converts conditional code (and virtual functions, in the case of the State pattern) into a table look-up. The main advantage of tables is their regularity: change the transition criteria by modifying data instead of changing program code. There are some disadvantages, however:
  3. Creating and destroying State objects. A common implementation trade-off worth considering is whether (1) to create State objects only when they are needed and destroy them thereafter versus (2) creating them ahead of time and never destroying them. The first choice is preferable when the states that will be entered aren't known at run-time, and contexts change state infrequently. This approach avoids creating objects that won't be used, which is important if the State objects store a lot of information. The second approach is better when state changes occur rapidly, so try to avoid destroying states, because they may be needed again shortly. Instantiation costs are paid once up-front, and there are no destruction costs at all. This approach might be inconvenient, though, because the Context must keep references to all states that might be entered.
  4. Using dynamic inheritance. Changing the behavior for a particular request could be accomplished by changing the object's class at run-time, but this is not possible in most object-oriented programming languages. There are some laboratory languages that suport this, but neither Java or C++ allow this.

Related Patterns

The Flyweight (195) pattern explains when and how State objects can be shared.

State
objects are often Singletons (127).

Catalog Behavioral Prev Next