State helps when behavior changes according to an object’s lifecycle state and conditionals are starting to dominate the design.
Allow an object to alter its behavior when its internal state changes so the object appears to change its class.
What the pattern is trying to do
Allow an object to alter its behavior when its internal state changes so the object appears to change its class.
What force creates the need
Behavior varies by lifecycle phase, and large conditional blocks are spreading state logic across the codebase.
How the pattern responds
Represent each meaningful state as an object that owns the behavior for that state and controls valid transitions.
How the moving parts fit together
A context delegates behavior to a state object, and state implementations may trigger transitions to other states.
Java example in the Order Management domain
package org.javaomnibus.ecommerce.gof.behavioral;
public interface OrderState {
void cancel(OrderContext context);
}
public final class PaidState implements OrderState {
@Override
public void cancel(OrderContext context) {
context.setState(new CancelledState());
}
}
public final class CancelledState implements OrderState {
@Override
public void cancel(OrderContext context) {
throw new IllegalStateException("Order already cancelled");
}
}
Step by step
- Each state owns behavior that was previously buried in conditionals.
- The context delegates behavior to the active state object.
- This keeps lifecycle rules closer to the states they belong to.
- State is about lifecycle-driven behavior, not just swappable policy.
Where this pattern helps
- When behavior changes by lifecycle phase or status
- When conditionals on state keep spreading and becoming error-prone
When a simpler design is better
- When state distinctions are too small to justify separate types
- When the real problem is choosing among algorithms rather than modeling lifecycle
What this pattern costs
- Adds more types and transitions to reason about
- Poorly designed states can still leak transition logic everywhere
How this fits today
State remains useful in Java for order lifecycles, workflow engines, payment flows, fulfillment stages, and protocol-style objects.
Where teams get it wrong
Turning every small status flag into a full state hierarchy can over-model a domain that only needed a few clear checks.