The State Design Pattern: Machines with Personality
Master the State Pattern in Java. Learn how to let an object alter its behavior when its internal state changes, replacing massive switch statements.
Moshiour Rahman
Advertisement
The Problem: Massive Switch Statements
Imagine coding a Vending Machine. It behaves differently depending on its state.
public void insertCoin() {
if (state == NO_COIN) {
state = HAS_COIN;
System.out.println("Coin accepted");
} else if (state == HAS_COIN) {
System.out.println("You can't insert another coin!");
} else if (state == SOLD_OUT) {
System.out.println("Machine is empty");
}
}
Now imagine you have 10 methods (ejectCoin, pressButton, dispense…) and 5 states. You end up with 50 if/else blocks.
Adding a new state (e.g., “Winner” state where you get free soda) essentially requires rewriting the whole class.
The Solution: The State Pattern
The State Pattern allows an object to alter its behavior when its internal state changes. It looks like the object changed its class. We move the logic into separate State classes.
Real-Life Analogy: Your Phone 📱
- Locked State: Pressing “Home” asks for code.
- Unlocked State: Pressing “Home” goes to dashboard.
- Camera State: Pressing “Home” takes a photo.
The “Home Button” is the same, but the internal State determines what happens.
Visualizing the Pattern

Implementation
1. The State Interface
public interface State {
void insertCoin();
void ejectCoin();
void pressButton();
void dispense();
}
2. Concrete States
public class NoCoinState implements State {
VendingMachine machine;
public NoCoinState(VendingMachine m) { this.machine = m; }
public void insertCoin() {
System.out.println("You inserted a coin");
machine.setState(machine.getHasCoinState()); // Transition!
}
public void ejectCoin() {
System.out.println("You haven't inserted a coin");
}
// ... other methods ...
}
public class HasCoinState implements State {
VendingMachine machine;
public HasCoinState(VendingMachine m) { this.machine = m; }
public void insertCoin() {
System.out.println("You can't insert another coin");
}
public void ejectCoin() {
System.out.println("Coin returned");
machine.setState(machine.getNoCoinState()); // Transition!
}
// ... other methods ...
}
3. The Context (Vending Machine)
public class VendingMachine {
State noCoinState;
State hasCoinState;
// ... other states
State state; // Current state
public VendingMachine() {
noCoinState = new NoCoinState(this);
hasCoinState = new HasCoinState(this);
state = noCoinState; // Initial state
}
public void insertCoin() {
state.insertCoin(); // Delegate to current state
}
// ...
}
Usage
VendingMachine vendingMachine = new VendingMachine();
vendingMachine.insertCoin();
// Output: You inserted a coin (State changes to HasCoin)
vendingMachine.insertCoin();
// Output: You can't insert another coin (Handled by HasCoinState)
In The Wild (Real World Examples)
1. TCP Connection
A TCP connection has states: LISTEN, ESTABLISHED, CLOSED.
The send() method behaves differently in each state (sends data vs throws error).
2. Order Processing Systems
New -> Paid -> Shipped -> Delivered.
A cancel() action works in New state but fails in Shipped state.
Cheat Sheet
| Feature | Details |
|---|---|
| Category | Behavioral |
| Problem Solved | Complex state machines, massive switch statements |
| Key implementation | Context class delegates calls to a State interface |
| Pros | Single Responsibility (Each state logic is isolated), Open/Closed (Add new states easily) |
| Cons | Class Explosion (Lots of small classes) |
Tips to Remember 🧠
- “Polymorphism replaces Switch”: This pattern is the ultimate example of replacing conditionals with polymorphism.
- Strategy vs State: They look identical (Context -> Interface).
- Strategy: Client chooses the strategy (plug-in).
- State: The object changes its own state internally (transitions).
Advertisement
Moshiour Rahman
Software Architect & AI Engineer
Enterprise software architect with deep expertise in financial systems, distributed architecture, and AI-powered applications. Building large-scale systems at Fortune 500 companies. Specializing in LLM orchestration, multi-agent systems, and cloud-native solutions. I share battle-tested patterns from real enterprise projects.
Related Articles
The Template Method Pattern: The Recipe for Success
Master the Template Method Pattern in Java. Learn how to define the skeleton of an algorithm in a superclass but let subclasses override specific steps.
JavaThe Strategy Design Pattern: Kill the If-Else Statements
Master the Strategy Pattern in Java. Learn how to replace complex if-else logic with interchangeable algorithms and follow the Open/Closed Principle.
JavaThe Memento Design Pattern: Time Travel for Objects
Master the Memento Pattern in Java. Learn how to capture and restore an object's internal state for undo/redo functionality.
Comments
Comments are powered by GitHub Discussions.
Configure Giscus at giscus.app to enable comments.