creational
State
Allow an object to alter its behavior when its internal state changes.
Some objects behave differently depending on what state they are in. An order that is draft, paid, shipped or cancelled allows different actions in each one.
Written with conditionals, every method starts by checking the state. The same checks appear again and again. Adding a state means finding and updating all of them, and missing one is easy.
State gives each state its own class. The object delegates to whichever state it is currently in, and that class knows how to behave.
A vending machine — idle shows items, has-money accepts selection, dispensing delivers product.
Key Concepts
1
One interface defines the actions available, such as pay(), ship() and cancel().
pay()ship()cancel()
2
Each state implements it in its own way. PaidState.ship() works. DraftState.ship() rejects the call, because you cannot ship something unpaid.
PaidState.ship()DraftState.ship()
3
The main object holds a reference to its current state and forwards calls to it. It contains no conditionals at all.
4
Transitions happen by replacing that reference. After pay() succeeds, the object swaps its state to PaidState, and every later call automatically follows the new rules.
pay()PaidState
When to use it
- Objects with distinct lifecycle phases
- UI components (enabled/disabled/loading/error)
- Game characters (idle/walking/jumping)
Watch out for
- State: object transitions itself, states know each other. Strategy: client injects, strategies are independent.
java
public interface OrderState {
void next(Order order);
void prev(Order order);
String getStatus();
}
public class PendingState implements OrderState {
public void next(Order o) { o.setState(new ProcessingState()); }
public void prev(Order o) { System.out.println("Already at initial"); }
public String getStatus() { return "PENDING"; }
}
public class Order {
private OrderState state = new PendingState();
public void setState(OrderState s) { this.state = s; }
public void nextPhase() { state.next(this); }
public String getStatus() { return state.getStatus(); }
}