Applied Design Patterns with Java
Behavioral :: State (305) {C ch 23}
Collaborations
- Context delegates state-specific requests to the current
ConcreteState object.
- A context may pass itself as an argument to the State object handling
the request. This lets the State object access the context if necessary.
- Context is the primary interface for clients. Clients can configure
a context with State objects. Once a context is configured, its clients don't have to deal with the State objects
directly.
- Either Context or the ConcreteState subclasses can decide which state
succeeds another and under what circumstances.
Consequences
The State pattern has the following consequences:
- It localizes state-specific behavior and partitions behavior
for different states. The State pattern
puts all behavior associated with a particular state into one object. Because all state-specific code lives in
a State subclass, new states and transitions can be added easily by defining new subclasses. An alternative is
to use data values to define internal states and have Context operations check the data explicitly. But that needs
look-alike conditional or case statements scattered throughout Context's implementation. Adding a new state could
require changing several operations, which complicates maintenance.
The State pattern avoids this problem but might introduce another, because the pattern distributes
behavior for different states across several State subclasses. This increases the number of classes and is less compact
than a single class. But such distribution is actually useful if there are many states, which would necessitate
large conditional statements.
Like long procedures, large conditional statements are undesirable. They are monolithic and tend to make the code
less explicit, which in turn makes them difficult to modify and extend. The State pattern offers a
better way to structure state-specific code. The logic that determines the state transitions doesn't reside in
monolithic if
or switch
statements but instead is partitioned between the State subclasses. Encapsulating each state transition and action in a
class elevates the idea of an execution state to full object status. That imposes structure on the code and makes
its intent clearer.
- It makes state transitions explicit. When an object defines its current state solely in terms of internal data
values, its state transitions have no explicit representation; they only show up as assignments to some variables.
Introducing separate objects for different states makes the transitions more explicit. Also, State objects
can protect the Context from inconsistent internal states, because state transitions are atomic from the Context's
perspective—they happen by rebinding one variable (the Context's State object variable), not several.
- State objects can be shared. If State objects have no instance variables—that is, the state they represent
is encoded entirely in their type—then contexts can share a State object. When states are shared in this way, they are essentially
Flyweights (195) with no intrinsic state, only behavior.
Catalog Behavioral Prev Next