What is the State design pattern, and how does it let an object change its behavior when its internal state changes?
answer
- Behavioral pattern: object appears to change its class
- Context delegates to current State object
- One class per state, no big switch
- Transition = swap the current state reference
- Open/Closed: new state = new class
basics
~20 sThe State pattern lets an object behave differently depending on what 'mode' it is in. Each mode is its own object with its own version of the methods, and the main object hands work to whichever mode it currently holds.
solid answer
~50 sThe State pattern is a behavioral design pattern that lets an object alter its behavior when its internal state changes, so it appears to change its class. You extract each state into its own class implementing a common State interface, and the main object (the 'context') holds a reference to the current state object and delegates behavior to it. Instead of giant if/else or switch blocks scanning a status field, each state class encapsulates the behavior valid in that state and decides which state to move to next. The result removes conditional branching, keeps each state's rules in one place, and makes adding a new state a matter of writing a new class rather than editing every method. In Java you typically model State as an interface or sealed type; transitions happen by the context (or the state itself) swapping the current state reference.
code
java · 22 linesinterface LightState {
LightState next();
String color();
}
final class Red implements LightState {
public LightState next() { return new Green(); }
public String color() { return "RED"; }
}
final class Green implements LightState {
public LightState next() { return new Yellow(); }
public String color() { return "GREEN"; }
}
final class Yellow implements LightState {
public LightState next() { return new Red(); }
public String color() { return "YELLOW"; }
}
class TrafficLight { // the Context
private LightState state = new Red();
void tick() { state = state.next(); } // delegate + transition
String show() { return state.color(); } // no switch anywhere
}go deeper
Can describe State as 'different behavior in different modes, one object per mode' and recognize it removes big switch statements.
Explains the three roles (context, state interface, concrete states), shows delegation, and can write a small state machine in Java.
Discusses where transitions belong, trade-offs vs. enum/switch, thread-safety of swapping state, and how sealed types model it cleanly.
Frames State within a broader state-machine design, weighs it against table-driven FSMs or workflow engines, and reasons about evolution, testing, and invariants across states.
## The problem State solves Many objects behave differently depending on a *mode* or *condition* they are in. A document can be in **Draft**, **Moderation**, or **Published**; a network connection can be **Open** or **Closed**; a vending machine can be **Awaiting Coin**, **Has Coin**, or **Dispensing**. The naive way to model this is a single field (e.g. `String status`) plus `if`/`switch` statements in every method that check the field and branch. This quickly becomes painful: the same `switch (status)` is copy-pasted into many methods, behavior for one state is scattered across the class, and adding a new state means hunting down and editing every method. This is a classic code smell. ## What the State pattern is The **State pattern** is a *behavioral* design pattern (one of the original "Gang of Four" patterns). Its definition: *allow an object to alter its behavior when its internal state changes; the object will appear to change its class.* It has three roles: 1. **Context** — the main object whose behavior varies (e.g. the connection, the document). It keeps a reference to a *current state* object and delegates the real work to it. 2. **State** — an interface (or abstract type) declaring the operations whose behavior depends on state. 3. **Concrete States** — one class per state, each implementing the State interface with the behavior valid *in that state*, and each responsible for deciding which state comes next (the **transition**). Key idea: the `if`/`switch` on a status field disappears. Instead of *one object with many branches*, you have *many small objects, one per state*, and polymorphism picks the right behavior automatically. ## How a call flows When client code calls a method on the context, the context simply forwards the call to its current state object: `currentState.handle(this)`. The state object does the work appropriate to that state and may tell the context to switch to a new state (`context.setState(new NextState())`). The next call therefore behaves differently — the object "appears to change its class." ## Transitions: who decides? There are two common placements for the transition logic: - **State-driven:** each concrete state knows its valid successors and calls `context.setState(...)`. This keeps transition rules next to the behavior, at the cost of states knowing about each other. - **Context-driven:** the context decides the next state. This centralizes the state machine but can re-grow the conditionals you were trying to remove. ## Why it's good - **Removes conditionals** — replaces sprawling `switch` blocks with polymorphism. - **Single Responsibility** — each state's rules live in exactly one class. - **Open/Closed** — a new state is a new class, not edits across existing methods. - **Explicit, legal transitions** — illegal moves can simply not be coded, or throw. ## Costs - More classes (one per state) — overkill if you have only two trivial states. - Transition logic can be hard to follow if scattered across many state classes. ## Tiny example A `TrafficLight` with `Red`, `Green`, `Yellow` states: calling `next()` on the light delegates to the current state, which returns/sets the following color. No `switch (color)` anywhere. In Java you implement State as an `interface` or, in modern Java, a `sealed interface` with `record`/class implementations, optionally an `enum` when states are simple and fixed.
- Where should the transition logic live — in the context or in the state objects?Both are valid. Putting it in each state keeps transition rules next to the behavior (states must know their successors); putting it in the context centralizes the state machine but risks re-introducing conditionals. Choose by how complex and how shared the transition rules are.
- When is the State pattern overkill?When there are only one or two trivial states with little behavior — a simple boolean or enum with a couple of branches is clearer than a class hierarchy. State pays off once behavior per state is substantial or states are many.
saying these in an interview costs you the question
- Confusing State with a plain status field plus switch statements — that is exactly what State replaces.
- Thinking the context implements the varying behavior itself; the whole point is delegation to state objects.
- Claiming State requires a framework — it is plain OOP, no library needed.
- Saying the object literally changes its Java class; it changes its current-state reference and only *appears* to change class.