State Interface
The State pattern allows an object to alter its behavior when its internal state changes.
Core Structure
┌──────────────────────────┐
│ Context │
├──────────────────────────┤
│ - state: State │
├──────────────────────────┤
│ + request() │
│ + setState(State) │
└──────────┬───────────────┘
│ uses
▼
┌──────────────────────────┐
│ «interface» │
│ State │
├──────────────────────────┤
│ + handle(context) │
└──────────┬───────────────┘
│ implemented by
┌─────┴──────┐
│ │
┌────┴─────┐ ┌───┴──────┐
│ StateA │ │ StateB │
└──────────┘ └──────────┘
State Interface
public interface State {
void handle(VendingMachine machine);
// Optional: available operations in this state
default void insertCoin(VendingMachine machine) {
throw new IllegalStateException("Cannot insert coin in this state");
}
default void selectItem(VendingMachine machine) {
throw new IllegalStateException("Cannot select item in this state");
}
default void dispense(VendingMachine machine) {
throw new IllegalStateException("Cannot dispense in this state");
}
}
Context Class
public class VendingMachine {
private State state;
private int balance;
private Item selectedItem;
public VendingMachine() {
this.state = new IdleState(); // Initial state
this.balance = 0;
}
public void setState(State state) {
this.state = state;
}
public void insertCoin(int amount) {
state.insertCoin(this);
}
public void selectItem(String itemId) {
state.selectItem(this);
}
public void dispense() {
state.dispense(this);
}
// Getters
public int getBalance() { return balance; }
public void addBalance(int amount) { this.balance += amount; }
public Item getSelectedItem() { return selectedItem; }
public void setSelectedItem(Item item) { this.selectedItem = item; }
}
How It Works
IdleState.insertCoin(machine)
→ machine.addBalance(amount)
→ machine.setState(HasCoinState)
HasCoinState.selectItem(machine, itemId)
→ machine.setSelectedItem(item)
→ machine.setState(ItemSelectedState)
ItemSelectedState.dispense(machine)
→ dispense item
→ machine.setState(IdleState)
Concrete States
Each concrete state implements behavior specific to that state.
Idle State
public class IdleState implements State {
@Override
public void insertCoin(VendingMachine machine) {
machine.addBalance(coin);
System.out.println("Coin inserted: $" + coin);
machine.setState(new HasCoinState());
}
@Override
public void selectItem(VendingMachine machine) {
System.out.println("Insert coin first");
}
@Override
public void dispense(VendingMachine machine) {
System.out.println("Insert coin and select item first");
}
}
Has Coin State
public class HasCoinState implements State {
@Override
public void insertCoin(VendingMachine machine) {
machine.addBalance(coin);
System.out.println("Additional coin inserted");
}
@Override
public void selectItem(VendingMachine machine, String itemId) {
Item item = inventory.get(itemId);
if (item == null) {
System.out.println("Item not found");
return;
}
if (machine.getBalance() < item.getPrice()) {
System.out.println("Insufficient balance");
return;
}
machine.setSelectedItem(item);
machine.setState(new DispensingState());
}
@Override
public void dispense(VendingMachine machine) {
System.out.println("Select an item first");
}
}
Dispensing State
public class DispensingState implements State {
@Override
public void dispense(VendingMachine machine) {
Item item = machine.getSelectedItem();
int change = machine.getBalance() - item.getPrice();
// Dispense item
inventory.remove(item.getId());
System.out.println("Dispensing: " + item.getName());
// Return change
if (change > 0) {
System.out.println("Change: $" + change);
}
// Reset and go to idle
machine.setSelectedItem(null);
machine.setState(new IdleState());
}
}
State Diagram
┌──────────┐ insertCoin ┌──────────┐
│ Idle │───────────────▶│ HasCoin │
└──────────┘ └────┬─────┘
│
selectItem
│
▼
┌──────────┐ dispense ┌──────────┐
│ Idle │◀───────────────│Dispensing│
└──────────┘ └──────────┘
Context Class
The Context class maintains the current state and delegates behavior to it.
Order Processing Example
public class OrderContext {
private OrderState state;
private Order order;
public OrderContext(Order order) {
this.order = order;
this.state = new NewOrderState();
}
public void process() {
state.process(this);
}
public void cancel() {
state.cancel(this);
}
public void ship() {
state.ship(this);
}
public void deliver() {
state.deliver(this);
}
public void setState(OrderState state) {
this.state = state;
System.out.println("State changed to: " + state.getName());
}
public Order getOrder() { return order; }
}
// States
public interface OrderState {
String getName();
void process(OrderContext context);
void cancel(OrderContext context);
void ship(OrderContext context);
void deliver(OrderContext context);
}
public class NewOrderState implements OrderState {
public String getName() { return "NEW"; }
public void process(OrderContext ctx) {
// Process payment
ctx.setState(new ProcessingState());
}
public void cancel(OrderContext ctx) {
ctx.setState(new CancelledState());
}
public void ship(OrderContext ctx) {
throw new IllegalStateException("Cannot ship new order");
}
public void deliver(OrderContext ctx) {
throw new IllegalStateException("Cannot deliver new order");
}
}
public class ProcessingState implements OrderState {
public String getName() { return "PROCESSING"; }
public void process(OrderContext ctx) {
throw new IllegalStateException("Already processing");
}
public void cancel(OrderContext ctx) {
ctx.setState(new CancelledState());
}
public void ship(OrderContext ctx) {
ctx.setState(new ShippedState());
}
public void deliver(OrderContext ctx) {
throw new IllegalStateException("Cannot deliver before shipping");
}
}
public class ShippedState implements OrderState {
public String getName() { return "SHIPPED"; }
public void process(OrderContext ctx) {
throw new IllegalStateException("Already shipped");
}
public void cancel(OrderContext ctx) {
throw new IllegalStateException("Cannot cancel shipped order");
}
public void ship(OrderContext ctx) {
throw new IllegalStateException("Already shipped");
}
public void deliver(OrderContext ctx) {
ctx.setState(new DeliveredState());
}
}
public class DeliveredState implements OrderState {
public String getName() { return "DELIVERED"; }
// All methods throw - terminal state
}
public class CancelledState implements OrderState {
public String getName() { return "CANCELLED"; }
// All methods throw - terminal state
}
State Transition Table
┌───────────┬─────────┬──────────┬────────┬─────────┐
│ Current │ process │ cancel │ ship │ deliver │
├───────────┼─────────┼──────────┼────────┼─────────┤
│ NEW │ → PROC │ → CANCEL │ ERROR │ ERROR │
│ PROCESSING│ ERROR │ → CANCEL │ → SHIP │ ERROR │
│ SHIPPED │ ERROR │ ERROR │ ERROR │ → DELIV │
│ DELIVERED │ ERROR │ ERROR │ ERROR │ ERROR │
│ CANCELLED │ ERROR │ ERROR │ ERROR │ ERROR │
└───────────┴─────────┴──────────┴────────┴─────────┘
Benefits of State Pattern
- Eliminates if/else chains: No more switch(state) everywhere
- Single Responsibility: Each state class handles one state
- Open-Closed: Add new states without modifying existing
- Clear transitions: State transitions are explicit
- Encapsulated behavior: Each state encapsulates its behavior
Practice Problems
Design a scalable State Pattern system. Cover high-level architecture, data model, and API design.
Solution
// Complete system design:
// - Functional + Non-functional requirements
// - Capacity estimation
// - Data model (SQL/NoSQL choice)
// - API endpoints
// - Component architecture
// - Scaling strategy
// - Monitoring & reliabilityHow would you scale State Pattern to handle 10x the current load? Identify bottlenecks and solutions.
Solution
// Scaling approach:
// 1. Load balancing
// 2. Database sharding/replication
// 3. Cache layer (Redis)
// 4. CDN for static assets
// 5. Async processing (queues)
// 6. Microservices decompositionAnalyze potential failure modes for State Pattern and design mitigation strategies.
Solution
// Failure mitigation:
// 1. Redundancy (multi-AZ)
// 2. Circuit breakers
// 3. Retry with backoff
// 4. Dead letter queues
// 5. Health checks
// 6. Graceful degradationQuiz
1. What does the State pattern allow?
2. What does the Context class do in the State pattern?
3. What does the State pattern replace?
4. What is a state transition?
5. What principle does the State pattern follow?
Flashcards
Question
What is the State pattern?
Click to reveal answer
Answer
Allows an object to alter behavior when internal state changes. Each state is a class implementing the state interface.
Question
What is the Context in State pattern?
Click to reveal answer
Answer
Maintains current state reference. Delegates behavior to current state. Provides setState() for state transitions.
Question
What does State pattern replace?
Click to reveal answer
Answer
Complex if/else or switch chains for state-dependent behavior. Replaces with polymorphic state objects.
Question
State vs Strategy pattern?
Click to reveal answer
Answer
State: behavior changes with internal state (automatic transitions). Strategy: algorithm selected externally (manual swapping).
Question
Real-world State pattern example?
Click to reveal answer
Answer
Vending machine states (idle, has coin, dispensing), Order states (new, processing, shipped, delivered), TCP connection states.
Revision Notes
Key Takeaways
- 1.State pattern allows objects to change behavior based on internal state
- 2.Each state is a class implementing the state interface
- 3.Context delegates behavior to current state and manages transitions
- 4.Replaces complex conditional logic with polymorphic state objects
- 5.State transitions are explicit and encapsulated in state classes
Interview Tips
- •Show State pattern for modeling order/game/workflow states
- •Explain how State eliminates complex conditional logic
- •Discuss state transitions and valid state changes
- •Compare State vs Strategy for algorithm selection
Cheat Sheet
State Pattern - Cheat Sheet
Purpose:
Object changes behavior when state changes.
Structure:
Context
├── state: State
├── setState(state)
└── request() → state.handle()
State (interface)
├── ConcreteStateA
└── ConcreteStateB
Key Points:
- Each state class handles one state
- State transitions via context.setState()
- Context delegates to current state
- Eliminates if/else chains
State vs Strategy:
| State | Strategy | |
|---|---|---|
| Selection | Internal (automatic) | External (manual) |
| Purpose | State-dependent | Algorithm selection |
| Transitions | Automatic | Manual |
Use Cases:
- Vending machine
- Order processing
- TCP connections
- Game states
- Traffic lights