Java 3 min read

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.

MR

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

State 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

FeatureDetails
CategoryBehavioral
Problem SolvedComplex state machines, massive switch statements
Key implementationContext class delegates calls to a State interface
ProsSingle Responsibility (Each state logic is isolated), Open/Closed (Add new states easily)
ConsClass 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

MR

Moshiour Rahman

Software Architect & AI Engineer

Share:
MR

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

Comments

Comments are powered by GitHub Discussions.

Configure Giscus at giscus.app to enable comments.