3.8 State
The State pattern lets an object change its behavior when its internal state changes, appearing as if it changed class. It refactors "a pile of state-branching if/else / switch" into "one object per state."
A vending machine is the classic example: the same "press dispense" behaves completely differently in the "no coin," "has coin," and "sold out" states. The lab below lets you operate a machine and watch the state migrate with each action.
Turn states into objects
interface State {
void insertCoin(Machine m);
void pressButton(Machine m);
}
class NoCoinState implements State {
public void insertCoin(Machine m) { m.setState(new HasCoinState()); }
public void pressButton(Machine m) { System.out.println("insert a coin first"); }
}
class Machine {
private State state = new NoCoinState();
void setState(State s) { this.state = s; }
void pressButton() { state.pressButton(this); } // delegate to current state
}The machine delegates each action to the current state object, which decides how to respond and which state to transition to. Adding a state means adding a class, not editing a screenful of conditionals. The traffic-light lab below lets you next() step by step, with each state knowing its own successor.
State vs Strategy: the twins' difference
Their UML structures are nearly identical (both delegate behavior to an interface object), but the intent differs:
| State | Strategy | |
|---|---|---|
| Who switches | Usually the object itself, by conditions | Usually the client, explicitly |
| Transitions? | States migrate to one another | Strategies don't usually transition |
| Focus | Behavior varies with state | Behavior varies with algorithm choice |
When to use it
When you find a class littered with if (status == X) ... else if (status == Y) ... repeated across multiple methods, State can dramatically clarify the code. Order lifecycles, TCP connection states, and game-character state machines are its home turf.