Design Patterns
Last updated Mar 5, 2002
State
|
กก |
Object Behavioral
Design Pattern
|
E.
Gamma, et al., Design Pattern : Elements of Reusable
Object-Oriented Software, Addison-Wesley, 1995, Chapter 5,
pp. 305-313
- Intent
- Also Known As
- Motivation
- Applicability
- Structure
- Participants
- Collaborations
- Consequences
- Implementation
- Sample Code
- Known Uses
- Related Patterns
Allow an object to alter its behavior when its internal state
changes. The object will appear to change its class.
Objects for States
Use the State pattern in either of the following cases:
- An object must change its behavior at run-time depending
on which state it is is in.
- Several operations have the same large multipart
conditional structure that depends on the object's state.
- Context
- defines the interface of interest to clients.
- maintains an instance of a ConcreteState subclass
that defines the current state.
- State
- defines an interface for encapsulating the
behavior associated with a particular state of
the Context.
- ConcreteState
- each subclass implements a behavior associated
with a state of the Context.
- Context delegates state-specific requests to the current
ConcreteState object.
- A Context may pass itself as an argument to the State
object so that the State object can access the context if
necessary.
- Context is the primary interface for clients. Clients
don't have to deal with the State objects directly.
- Either Context or the ConcreteState objects are
responsible for state transitions.
- It localizes state-specific behavior and partitions
behavior for different states.
- All state-specific behavior resides in its
associated State subclass, which makes it easy to
add new states and transitions.
- The State pattern avoids the problem of
scattering look-alike large conditional
statements throughout Context's implementation.
- Because the State pattern distributes behavior
for different states across several State
subclasses, it increases the number of classes
and is less compact than a single class.
- The logic that determines the state transitions
is partitioned between the State subclasses.
- It makes state transitions explicit.
- Introducing separate objects for different states
makes the state transitions more explicit than
defining the current state of an object solely in
terms of its internal data values.
- Because state transitions are atomic from the
Context's perspective, state objects can protect
the Context from inconsistent internal states.
- State objects can be shared.
- If State objects have no instance variables, they
are essentially flyweights with no intrinsic
state. Contexts can share such a State object.
- Who defines the state transitions?
- The State pattern does not specify which
participant defines the criteria for state
transitions.
- If the criteria are fixed, they can be
implemented entirely in the Context.
- It is generally more flexible and appropriate to
let the State subclasses themselves specify their
successor state and when to make the transition.
- A table-based alternative.
- Cargill uses tables to map inputs to state
transitions[Cargill92].
- The table-driven approach converts conditional
code or virtual functions into a table look-up.
- The State pattern models state-specific behavior,
whereas the table-driven approach focuses on
defining state transitions.
- The main advantage of tables is their regularity
in specifying and changing the transition
criteria.
- Disadvantages are:
- A table look-up is often less efficient
than a (virtual) function call.
- The transition criteria are less explicit
and therefore harder to understand.
- It's usually difficult to add actions to
accompany the state transitions.
- Creating and destroying State objects.
- Creating State objects only when they are needed
and destroying them thereafter.
- This approach preferable when states to
be entered aren't known at run-time, and
contexts change state infrequently.
- avoids creating objects that won't be
used.
- Creating State objects ahead of time and never
destroying them
- This approach is better when state
changes occur rapidly.
- Instantiation costs are paid once
up-front, and there are no destruction
costs at all.
- The Context must keep references to all
states that might be entered.
- Using dynamic inheritance
- Changing the behavior for a particular request
could be accomplished by changing the object's
class at run-time.
- Delegation-based languages like Self provide such
a mechanism and hence support the State pattern
directly.
- Objects in Self can delegate operations to other
objects to achieve a form of dynamic inheritance.
- The Flyweight pattern
explains when and how State objects can be shared.
- State objects are often Singletons.
Taewoong Jeon jeon@korea.ac.kr
Department of Computer Science, Korea University