🏛️ Design Principles & Patterns · Advanced

State & Chain of Responsibility in Java

Behavior by state objects; handlers passing requests along.

🧩 The mysteryThe same switch on mode appears in press(), hold() and render(). Then product adds a fourth mode. There's a pattern that deletes all three switches.

Switches everywhere

When behavior depends on a mode, the same switch tends to appear in every method. Each new mode means editing all of them, and missing one is a bug. Copying the switch into a helper, or swapping the enum for int constants, doesn't fix the shape.

void press() {
    switch (mode) {
        case OFF -> mode = ON;
        case ON -> mode = BLINK;
        case BLINK -> mode = OFF;
    }
}
// ...same switch in hold(), render()

State: behavior lives in the state

The State pattern gives each state its own class, or enum constant, implementing every behavior. The context delegates to its current state and replaces it on each transition. Each constant here owns its own next(), so the current state decides.

enum Light {
    RED { Light next() { return GREEN; } },
    GREEN { Light next() { return AMBER; } },
    AMBER { Light next() { return RED; } };
    abstract Light next();
}
🔮 Predict it

Three presses

What does this print?

enum Fan {
    OFF { Fan press() { return LOW; } },
    LOW { Fan press() { return HIGH; } },
    HIGH { Fan press() { return OFF; } };
    abstract Fan press();
}
void main() {
    IO.println(Fan.LOW.press().press().press());
}
  1. LOW
  2. HIGH
  3. OFF
Show the answer

Round 1: LOW to HIGH. Round 2: HIGH to OFF. Round 3: OFF back to LOW. No switch anywhere: each constant knows its successor, and the current state decides what happens.

Chain of Responsibility

Here, handlers are linked in a line. Each one either handles the request or passes it to the next. The sender only calls the first handler and never knows which one responds. Subclasses handle what they can and call super.handle(r) for the rest.

abstract class Handler {
    private Handler next;
    Handler then(Handler n) {
        next = n;
        return n;
    }
    void handle(Request r) {
        if (next != null) next.handle(r);
    }
}
🤔 Think first

Who approves $500?

Approvals: a team lead takes expenses under $100, a manager under $1,000, a director anything bigger. Chain: lead, manager, director. Who handles $500, and what does the submitter need to know?

Think about it, then reveal the answer

The lead sees it's over $100 and forwards it; the manager handles it. The submitter just calls the first handler, so adding or reordering approvers when the rules change doesn't affect it.

⚠️ The trap

Not every handler must act

Chain of Responsibility doesn't require every handler to process each request. Usually a handler either handles or forwards. Some chains, like servlet filters, let several handlers act in turn, but that's a choice. The real bug is a handler that does neither, silently dropping the request.

💼 In the real world

Chains and states at work

Servlet filters and Spring Security's filter chain, logging handlers and HTTP middleware are chains. Order workflows (new, paid, shipped, refunded), media players and game characters are classic State machines.

Key takeaways

  1. State: one class or enum constant per state
  2. Transitions replace the current state object
  3. Chain: each handler handles the request or passes it on
  4. The sender doesn't know which handler will respond

💡 A vending machine acts differently when empty, idle or paid; a support ticket climbs from bot to agent to manager.

🤯 Did you know?

An enum constant with its own body, like RED { ... }, is compiled into its own anonymous subclass of the enum. That's how each constant can carry a different next().

Practice questions

What does this print?

enum Light {
    RED { Light next() { return GREEN; } },
    GREEN { Light next() { return AMBER; } },
    AMBER { Light next() { return RED; } };
    abstract Light next();
}
void main() {
    IO.println(Light.AMBER.next().next());
}
  1. GREEN
  2. RED
  3. AMBER
Check your answer

GREEN. AMBER goes to RED, and RED goes to GREEN. Each constant owns its own transition, so there's no central switch.

Which pattern is this?

abstract class Handler {
    private Handler next;
    Handler then(Handler n) {
        next = n;
        return n;
    }
    void handle(Request r) {
        if (next != null) next.handle(r);
    }
}
  1. Chain of Responsibility
  2. State
  3. Composite
  4. Observer
Check your answer

Chain of Responsibility. Handlers are linked one after another; each subclass decides whether to handle a request or call super.handle() to pass it along.

Next: a folder whose size is the sum of its files and folders, and a loop that crashes when you delete while iterating.