The State Pattern (Behavioral) ©SoftMoore ConsultingSlide 1
Background The state of an object is an abstraction of its attribute values and links. Sets of values are grouped together into a state according to properties that affect gross behavior of the object. All objects of a class with the same state react in the same general way to an event; however, objects in different states may react differently to the same event. Sometimes the conceptual state of an object can be captured in a single attribute; e.g., using an integer value or the value of an enumerated type. ©SoftMoore ConsultingSlide 2
Background (continued) State-dependent behavior: The effect of calling a method depends not only on the method being called and the parameters passed to it, but also on the state of the object at the time the method is called. Most objects exhibit some state-dependent behavior. Some objects exhibit complex state-dependent behavior. ©SoftMoore ConsultingSlide 3
The behavior for a simple garage door opener could be described by the following state diagram: One way to implement a controller for the garage door opener would be to use conditional statements. Motivating Example (David Bernstein, James Madison University) ©SoftMoore ConsultingSlide 4 Open Closed close open lock EnteringLocked start unlock error unlock
public class Controller { private int state; // states private static final int ENTERING = 0; private static final int CLOSED = 1; private static final int LOCKED = 2; private static final int OPENED = 3; // actions private static final int ENTER = 0; private static final int CLOSE = 1; private static final int LOCK = 2; private static final int OPEN = 3; Motivating Example (continued) ©SoftMoore ConsultingSlide 5
public Controller() { setState(CLOSED); } private void setState(int state) { this.state = state; } Motivating Example (continued) ©SoftMoore ConsultingSlide 6
public void onChange(int action) { if (action == CLOSE)) { if (state == OPENED) { close(); setState(CLOSED); } if (action == LOCK) { if (state == CLOSED) { lock(); setState(LOCKED); }... Motivating Example (continued) ©SoftMoore ConsultingSlide 7
This implementation is difficult to understand and maintain. Consider the problem of adding a new state. The State design pattern provides an alternative way to implement the controller. Motivating Example (continued) ©SoftMoore ConsultingSlide 8
State Pattern Intent: Allow an object to alter its behavior when its internal state changes. The object will appear to change its class. Also Known As: Objects for States Slide 9©SoftMoore Consulting
State Pattern (continued) Applicability: Use the State pattern in either of the following cases: An object’s behavior depends on its state, and it must change its behavior at run-time depending on that state. Operations have large, multipart conditional statements that depend on the object’s state, and the state can be represented by one or more enumerated constants. Often, several operations will contain the same conditional structure. The State pattern puts each branch of the conditional in a separate class. ©SoftMoore ConsultingSlide 10
State Pattern (continued) ©SoftMoore ConsultingSlide 11 State handle() ConcreteStateB handle() Structure ConcreteStateC handle() ConcreteStateA handle() Context request() state state.handle()
State Pattern (continued) Participants 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 subclasses –each subclass implements a behavior associated with a state of the Context. ©SoftMoore ConsultingSlide 12
State Pattern (continued) Collaborations Context delegates state-specific requests to the current ConcreteState object. A context may pass itself as a parameter to the State object handling the request – allows the State object to access the context. Context provides the primary interface to clients. Clients can configure a context with State objects, but once a context is configured, its clients don’t have to deal with State objects directly. ©SoftMoore ConsultingSlide 13
State Pattern (continued) Collaborations (continued) Either Context or the ConcreteState subclasses can decide which state succeeds another and under what circumstances. ©SoftMoore ConsultingSlide 14
State Pattern (continued) Consequences: The State pattern Localizes state-specific behavior and partitions behavior for different states. Since all state-specific code lives in a State subclass, new states and transitions can be added easily by defining new subclasses. The alternative would require modification to several methods to add new braches to conditional statements. Makes state transitions explicit. State transitions are achieved by one variable, the Context object’s state variable. ©SoftMoore ConsultingSlide 15
State Pattern (continued) Consequences (continued) Allows state objects to be shared. State objects can be shared if they have no instance variables; i.e., if the state they represent is encoded entirely in their methods. In this case, the state objects are essentially flyweights with no intrinsic state, only behavior. ©SoftMoore ConsultingSlide 16
State Pattern (continued) Implementation Who defines the State transitions. If the criteria for state transitions are fixed, then they can be implemented entirely in the Context. Alternatively, the State subclasses can specify when to make the transition and the appropriate successor state. A table-based alternative. It may be possible to use a transition table to map inputs to successor states. This approach converts conditional code to a table look-up. ©SoftMoore ConsultingSlide 17
State Pattern (continued) Implementation (continued) Creating and destroying state objects. Should state objects be created only when they are needed and destroyed thereafter, or should all state objects be created ahead of time and never destroyed? The first alternative might be preferable when contexts change state infrequently. The second alternative pays the costs for instantiation up-front. Using dynamic inheritance. Some programming languages effectively allow an object to change its class at run-time. ©SoftMoore ConsultingSlide 18
Motivating Example Revisited public interface State { public void enter(); public void close(); public void lock(); public void open(); } ©SoftMoore ConsultingSlide 19
Motivating Example Revisited (continued) public class Closed implements State { private Controller controller; public Closed(Controller controller) { this.controller = controller; } public void enter() { // ignore } public void close() { // ignore } ©SoftMoore ConsultingSlide 20
Motivating Example Revisited (continued) public void lock() {... // code to lock the door controller.changeState(getState(LOCKED); } public void open() {... // code to open the door controller.changeState(getState(OPENED)); } ©SoftMoore ConsultingSlide 21
Guidelines on Using the State Pattern The state pattern is most beneficial when a class has several methods with conditional/multiway branches that depend on the state, or when it has a single such method that is complicated and difficult to understand. If a class has only one method with a conditional/multiway branch that depends on the state, and if that method has a simple, coherent, and regular structure, then the benefits obtained by using the state pattern might be minimal. ©SoftMoore ConsultingSlide 22
Related Patterns The Flyweight pattern explains when and how State objects can be shared. State objects are often Singletons. State and Strategy have similar UML diagrams, but they differ in their intent. –A Strategy encapsulates an algorithm, whereas a State encapsulates state information and state-dependent behavior. –Clients often select the appropriate Strategy but not the State. (But Clients can sometimes select the initial state.) –Both State and Strategy are examples of composition with delegation. ©SoftMoore ConsultingSlide 23
References State pattern (Wikipedia) State Design Pattern (SourceMaking) How to implement state-dependent behavior: Doing the State pattern in Java (Eric Armstrong, JavaWorld) state-dependent-behavior.html The State Pattern (by David Bernstein, JMU) ©SoftMoore ConsultingSlide 24