Overview
The State pattern lets an object change its behavior when its internal state changes, as if it changed its class. Each state is a separate class implementing the same interface; the context (a vending machine, an order, an elevator) delegates every request to its current state object, and states decide transitions.
It replaces large switch statements on a status field that appear in every method (if state == IDLE ... else if state == HAS_MONEY ...). With State, adding a new state means adding a class, and each state's rules are in one place. It is the standard implementation of a state diagram in LLD interviews.
Pressing the power button does different things when the phone is locked, unlocked, or off. The button is the same; the current mode decides the behavior and which mode comes next.
When to use it
- An object's behavior depends heavily on its current state.
- Methods contain the same switch on a status field.
- Machines and lifecycles: vending machine, ATM, elevator, order, traffic light, document workflow.
Where it shows up in interviews
Recognize it when: device reacts differently to the same input by mode.
- Design a vending machine
- Design an ATM
- Design an elevator system
Recognize it when: status with allowed transitions.
- Design an order system
- Design a document approval workflow
Where it is used in real software
Classic example from the Gang of Four book: TCPConnection delegates to TCPEstablished, TCPListen, and TCPClosed.
Idle, running, jumping, and attacking states handle input differently.
Document approval and payment flows are modeled as state machines (Spring State Machine, XState).
Key terms
- Context
- The object whose behavior changes (VendingMachine).
- State interface
- Operations every state handles (insertCoin, select).
- Concrete state
- Behavior for one state (HasMoneyState).
- Transition
- A state setting the context's next state.
How it works, step by step
- 1Draw the state diagram
States, events, transitions.
- 2Define the state interface
One method per event.
- 3Implement a class per state
Handle each event: act, transition, or reject.
- 4Context delegates
machine.insertCoin() calls state.insertCoin(machine).
- 5States set the next state
context.setState(new DispensingState()).
STEP 1Context delegates insertCoin(25) to IdleState, which adds credit and switches to HasMoneyState.
How each state handles events
Vending machine, item price 100
| State | insertCoin | select | cancel |
|---|---|---|---|
| Idle | Add credit, go HasMoney | Reject: insert money first | Nothing to refund |
| HasMoney | Add credit | If credit >= 100: Dispensing | Refund, go Idle |
| Dispensing | Reject: busy | Reject: busy | Reject: busy |
| SoldOut | Refund immediately | Reject: sold out | Refund |
NOWState: Idle | insertCoin: Add credit, go HasMoney | select: Reject: insert money first | cancel: Nothing to refund
Each row is one class. No method in the machine contains a switch on state.
Implementation
public interface MachineState { void insertCoin(VendingMachine m, int cents); void select(VendingMachine m, String code); void cancel(VendingMachine m);} public final class VendingMachine { private MachineState state = new IdleState(); private int credit; private final Map<String, Integer> prices = new HashMap<>(); private final Map<String, Integer> stock = new HashMap<>(); public void insertCoin(int cents) { state.insertCoin(this, cents); } public void select(String code) { state.select(this, code); } public void cancel() { state.cancel(this); } void setState(MachineState s) { state = s; } void addCredit(int c) { credit += c; } int credit() { return credit; } int refund() { int r = credit; credit = 0; return r; } int price(String code) { return prices.getOrDefault(code, Integer.MAX_VALUE); } boolean inStock(String code) { return stock.getOrDefault(code, 0) > 0; } void dispense(String code) { stock.merge(code, -1, Integer::sum); credit -= price(code); } boolean anyStock() { return stock.values().stream().anyMatch(q -> q > 0); } public void load(String code, int price, int qty) { prices.put(code, price); stock.merge(code, qty, Integer::sum); }} final class IdleState implements MachineState { public void insertCoin(VendingMachine m, int cents) { m.addCredit(cents); m.setState(new HasMoneyState()); } public void select(VendingMachine m, String code) { System.out.println("Insert money first"); } public void cancel(VendingMachine m) {}} final class HasMoneyState implements MachineState { public void insertCoin(VendingMachine m, int cents) { m.addCredit(cents); } public void select(VendingMachine m, String code) { if (!m.inStock(code)) { System.out.println("Item unavailable"); return; } if (m.credit() < m.price(code)) { System.out.println("Price: " + m.price(code)); return; } m.dispense(code); System.out.println("Dispensed " + code + ", change " + m.refund()); m.setState(m.anyStock() ? new IdleState() : new SoldOutState()); } public void cancel(VendingMachine m) { System.out.println("Refund " + m.refund()); m.setState(new IdleState()); }} final class SoldOutState implements MachineState { public void insertCoin(VendingMachine m, int cents) { System.out.println("Sold out, returning " + cents); } public void select(VendingMachine m, String code) { System.out.println("Sold out"); } public void cancel(VendingMachine m) {}}Complexity and performance
Delegation to current state.
Plus interface and context.
Trade-offs
For simple transitions with little behavior, an enum table is shorter; State shines when behavior per state differs a lot.
States deciding transitions spreads the diagram across classes; a central table keeps it visible.
Variants and related techniques
Same structure; strategies are chosen by clients, states switch themselves as events occur.
Java enums with abstract methods implement small state machines compactly.
Stateless state objects can be shared instances.
Common mistakes
- Keeping state data inside state objects that get replaced.
Fix: Keep shared data (credit, stock) in the context; states hold behavior.
- Forgetting invalid events.
Fix: Every state must handle every event explicitly (reject or ignore).
Interview questions
How does the State pattern differ from Strategy?
Both delegate to an interface. With Strategy, the client selects the algorithm and it rarely changes. With State, the object moves between states itself as events happen, and each state determines the next.
Why use State instead of a switch on status?
A switch repeated in every method grows with each new state and mixes all rules together. State puts each state's behavior and transitions in its own class, following SRP and OCP.
Practice problems
| Problem | Difficulty | What it trains |
|---|---|---|
| Traffic light with pedestrian button | Easy | Timed transitions. |
| Vending machine with State pattern | Medium | Events and refunds. |
| ATM session states (card, PIN, transaction) | Medium | Security rules. |