Learn the State Design Pattern
This is the 20th post in a series on design patterns.
State is a behavioral design pattern that lets an object alter its behavior when its internal state changes. It appears as if the object changed its class.
Imagine that you have a class called Order for ordering Pizzas. The order can be in one of four states: Confirmed, Baked, Dispatched, or Delivered. The next method of the order works a little bit differently in each state. For instance, in Confirmed, it moves the order state to Baked. In Baked, it moves to Dispatched, and in Dispatched, it moves to Delivered.
State machines are usually implemented with a lot of conditional operators that select the appropriate behavior based on the object’s current state.
Once we add more and more states and state-dependent behaviors to the Order class, the biggest weakness of a state machine based on conditionals becomes apparent.
State Design Pattern
The State design pattern suggests creating new classes for all the possible states of an object and extracting all state-specific behaviors into these classes.
Instead of implementing all behaviors on its own, the original object called context stores a reference to one of the state objects that represents its current state and delegated all state-related work to that object. Replace the active state object with another object representing the new state to transition the context. This is only possible if all state classes follow the same interface and the context interacts with these objects through the interface.
While it looks similar to the Strategy pattern, there is one key difference. State patterns involve states that know about each other and initiate transitions from one state to another, whereas strategies are rarely aware of each other.
UML Class Diagram

Not familiar with UML Class Diagram? I have written a detailed post on the UML Class diagram.
Implementation steps
- Decide which class will act as the context. It could be an existing class that contains state-dependent code or a new class if the state-specific code is spread across multiple classes.
- Define the state interface. It may mirror all the methods declared in the context, but only those containing state-specific behavior should be aimed at.
- Create a class for every state that derives from the state interface. Then, go through the methods of the context and copy all the code related to that state into your class.
- Add a reference field of the state interface type and a public setter that allows it to be overridden in the context class.
- Replace the empty state conditionals in the method of the context with calls to the corresponding methods of the state object.
- Create an instance of one of the state classes and pass it to the context to switch its state.
Source Code Implementation
The Order (Context) class stores a reference to one of the concrete state objects and delegates all state-specific operations to it. The context communicates with the state object using the state interface. There is a setter in the context for passing a new state object.
package com.learncsdesign; | |
public class Order { | |
private OrderState state = new ConfirmedState(); | |
public OrderState getState() { | |
return state; | |
} | |
public void setState(OrderState state) { | |
this.state = state; | |
} | |
public void nextState() { | |
state.next(this); | |
} | |
public void printStatus() { | |
state.printStatus(); | |
} | |
} |
State-specific methods are defined in the OrderState (State) interface.
package com.learncsdesign; | |
public interface OrderState { | |
public void next(Order order); | |
public void printStatus(); | |
} |
ConfirmedState, BakedState, DispatchedState & DeliveredState each implement their own state-specific methods. Concrete State objects may store a reference to the context object. This reference allows the state to fetch any required information from the context object, as well as initiate state transitions.
package com.learncsdesign; | |
public class ConfirmedState implements OrderState { | |
@Override | |
public void next(Order order) { | |
order.setState(new BakedState()); | |
} | |
@Override | |
public void printStatus() { | |
System.out.println("Order Confirmed!"); | |
} | |
} |
package com.learncsdesign; | |
public class BakedState implements OrderState { | |
@Override | |
public void next(Order order) { | |
order.setState(new DispatchedState()); | |
} | |
@Override | |
public void printStatus() { | |
System.out.println("Order Baked!"); | |
} | |
} |
package com.learncsdesign; | |
public class DispatchedState implements OrderState { | |
@Override | |
public void next(Order order) { | |
order.setState(new DeliveredState()); | |
} | |
@Override | |
public void printStatus() { | |
System.out.println("Order Dispatched!"); | |
} | |
} |
package com.learncsdesign; | |
public class DeliveredState implements OrderState { | |
@Override | |
public void next(Order order) { | |
order.setState(null); | |
} | |
@Override | |
public void printStatus() { | |
System.out.println("Order Delivered Yeh!"); | |
} | |
} |
Likewise, contexts and concrete states can both set the next state of the context and perform the actual state transition by replacing the state object linked to the context.
package com.learncsdesign; | |
public class StateClient { | |
public static void main(String[] args) { | |
Order order = new Order(); | |
order.printStatus(); | |
order.nextState(); | |
order.printStatus(); | |
order.nextState(); | |
order.printStatus(); | |
order.nextState(); | |
order.printStatus(); | |
} | |
} |
// Output Order Confirmed! Order Baked! Order Dispatched! Order Delivered Yeh!
When To Apply State Design Pattern
- Use the State design pattern when you have an object that behaves differently depending on its current state, the number of states is large and the state-specific code changes frequently.
- The pattern should be used whenever you have a class polluted with massive conditionals that alter the behavior of the class according to the values of its fields.
- If you have a lot of duplicate code across similar states and transitions of a condition-based state machine, use the State design pattern.
Pros of State Design Pattern
- Separate the code related to different states into separate classes.
- Introduce new states without changing existing state classes.
- Simplify the context code by eliminating bulky state machine conditionals.