Behavioral pattern
State
An object's behavior changes with its internal state — model each state as its own object instead of branching on a status flag everywhere.
✗ The problem
Behavior branches on a status string
The same if / else if chain on status gets repeated in every
method — pay(), ship(), cancel()…
class Order {
pay() {
if (this.status === 'pending') this.status = 'paid';
else if (this.status === 'paid') { /* no-op */ }
else throw new Error('bad state');
}
ship() {
if (this.status === 'paid') this.status = 'shipped';
else if (this.status === 'pending') throw new Error('pay first');
// cancel() repeats the same chain again…
}
}
Adding one state means editing every method. Illegal transitions like
ship() before pay() are easy to allow by mistake.
✓ The pattern
→
→
→
Each state is its own object
A state object knows only its own legal moves. The context (Order) just
delegates to whichever state object is current.
class PendingState {
pay(order) { order.setState(new PaidState()); }
ship(order) { throw new Error('pay first'); }
}
// Order.pay() just calls: this.state.pay(this)
Pending
Paid
Shipped
Delivered
✓ See it live
→
→
→
Fire an event — only legal moves happen
The order starts Pending. Click an event; the current state object decides what's next — illegal events are rejected.
Pending
Paid
Shipped
Delivered
Cancelled
from Pending / Paid
Current state: Pending
✓ Takeaway
Explicit states, impossible transitions
- Encapsulate state-specific behavior inside each state object, not the context.
- Transitions become explicit — a state that doesn't implement an event simply can't do it.
- Kills the giant
if / else ifchain repeated across every method. - Looks like Strategy structurally, but intent differs: states swap themselves as the object's condition changes; a Strategy is picked by the client.
- Careful: many states means many small classes — worth it once branching gets messy.
🎯 Principle applied: State applies Open/Closed (a new state is a new class; existing states untouched) and SRP (each state owns its behavior), replacing sprawling status conditionals.
Back to all topics →