Command Palette

Search for a command to run...

PHASE 2Beginner ~8 min· topic 16 of 22Behavioral

Behavioral 4 — State

In one line

An object changes behavior when its state changes — state logic moves from if/else soup into per-state classes. The vending machine pattern.

0/22 · 0%

Key ideas

  1. 01

    Solves: objects with a few explicit states and transitions (vending, ATM, elevators, order lifecycle).

  2. 02

    Context delegates to a State object; each State decides the next State.

  3. 03

    State vs Strategy: same shape; Strategy is caller-selected, State transitions itself.

  4. 04

    Illegal transition handling lives inside each state (e.g. dispense while empty).

  5. 05

    Real-life example: a traffic light. Pressing the pedestrian button does different things when it's green, yellow, or red. The light's behaviour depends on its current state.

  6. 06

    Interview tip: draw the state diagram (circles = states, arrows = events) BEFORE writing code. It shows every allowed and forbidden move at a glance.

Java / Spring map

  • →

    Spring StateMachine; Long running workflows (order status) are State at enterprise scale.

Code & diagrams

VendingState.javajava

Vending machine core — the flagship State pattern example.

public class VendingMachine {
  private State state = new IdleState();
  private int balance = 0;

  public void setState(State s) { this.state = s; }
  public int balance() { return balance; }
  public void addMoney(int c) { balance += c; state.onMoney(this, c); }
  public void select(String item) { state.onSelect(this, item); }
  public void dispense() { state.onDispense(this); }

  public void doDispense(String item) {
    System.out.println("dispense: " + item + " (balance " + balance + ")");
    balance = 0;
  }
}

public interface State {
  void onMoney(VendingMachine m, int cents);
  void onSelect(VendingMachine m, String item);
  void onDispense(VendingMachine m);
}

public class IdleState implements State {
  public void onMoney(VendingMachine m, int c) { m.setState(new HasMoneyState()); }
  public void onSelect(VendingMachine m, String i) { throw new IllegalStateException("insert coins first"); }
  public void onDispense(VendingMachine m)      { throw new IllegalStateException("nothing selected"); }
}

public class HasMoneyState implements State {
  public void onMoney(VendingMachine m, int c) { /* accumulate more */ }
  public void onSelect(VendingMachine m, String i) {
    if (!inventoryHas(m, i)) throw new IllegalStateException("sold out");
    if (m.balance() >= priceOf(i)) m.setState(new DispenseState(i));
    else throw new IllegalStateException("insufficient funds");
  }
  public void onDispense(VendingMachine m) { throw new IllegalStateException("select first"); }
}

public class DispenseState implements State {
  private final String item;
  public DispenseState(String item) { this.item = item; }
  public void onMoney(VendingMachine m, int c) { throw new IllegalStateException("wait"); }
  public void onSelect(VendingMachine m, String i) { throw new IllegalStateException("dispensing"); }
  public void onDispense(VendingMachine m) { m.doDispense(item); m.setState(new IdleState()); }
}

Explain without notes

01

What makes each state class an OCP win over a big switch on state?

Practice

01

Add a SellOutState (item empty → refund promo) and wire its transitions.

Trade-offs

  • ↔

    States multiply fast; if transitions are simple, an enum with a transition table is often enough.

Completion checklist

  • I can draw the state diagram first, then code one class per state with illegal moves rejected.

Back to phase