Phase 6 · Design patterns · Topic 6.10

State

Should know

Lets an object change its behaviour when its internal state changes, by putting each state's behaviour in its own class.

Not started

Step 1 Understand it

The problem it solves. Objects with modes (an order that's paid or shipped, a machine that's idle or dispensing) often end up with if/else on a status field in every method, and invalid actions slip through.

Watch it happen

AnimationState: each mode is an object that knows what each event means
Read the animation as text
  1. A vending machine reacts to the same button differently depending on its mode. Each mode is a State class that handles every event and decides the next state.
  2. Idle + "select an item": not allowed yet. The Idle state answers with a clear message instead of doing something wrong.
  3. Idle + "insert coin": valid. Idle handles it and moves the machine to HasCoin.
  4. HasCoin + "insert coin" again: this state already holds a coin, so it says so. Same event, different behaviour — no if/elif on a status variable anywhere.
  5. HasCoin + "select": move to Dispensing, which drops the item and returns the machine to Idle.
  6. Back to Idle, ready for the next customer. The machine just forwards every event to its current state object.

Picture it

stateDiagram-v2
  [*] --> Idle
  Idle --> HasCoin: insert a coin
  HasCoin --> Idle: press the button, snack given
  HasCoin --> HasCoin: insert a coin, already has one
  Idle --> Idle: press the button, asks for a coin
Circles are states; arrows are . The same event (pressing the button) does different things depending on the current state.

The idea

A vending machine reacts differently to 'insert coin' when it's idle, when it already has money, or when it's sold out. Instead of an if/elif on a status variable inside every method, each state is a that handles the events and decides the next state.

How it works, step by step

  1. Draw the : states as circles, events as arrows between them.
  2. Create one class per state, with one method per event.
  3. Each method does what's valid in that state, and may move the object to a new state.
  4. The main object holds its current state and forwards every event to it.
  5. An event that isn't valid in a state returns a clear 'not allowed' instead of doing something wrong.

Analogy

A traffic light: what happens on the next tick depends on whether it's red, amber or green, and each colour knows which comes next.

Where the analogy breaks

A traffic light has three simple states. Real systems can have many states and transitions, so draw the state diagram first, or the classes become hard to follow.

Example

An order's life (created → paid → shipped → delivered, or cancelled), vending machines, elevators, network connections.

Must-know points

  • Each state class handles the events that are valid in that state.
  • Transitions are explicit; invalid actions get a clear .
  • Start by drawing a state diagram.
  • A cousin of , but here the object changes its own behaviour.

Common mistakes

  • States that know too much about each other.
  • Forgetting some events in some states (like cancel while dispensing).
python
class Idle:
    def insert_coin(self, machine):
        machine.state = HasCoin()
        return "coin accepted"
    def press(self, machine):
        return "insert a coin first"

class HasCoin:
    def insert_coin(self, machine):
        return "already has a coin"
    def press(self, machine):
        machine.state = Idle()
        return "here is your snack"

class VendingMachine:
    def __init__(self): self.state = Idle()
    def insert_coin(self): return self.state.insert_coin(self)
    def press(self): return self.state.press(self)

Step 2 Go further (free, optional)

Optional. The notes above are written to be enough on their own. These free resources give a second explanation and extra practice.

Step 3 Practise

Try each exercise yourself first: on paper, out loud or in code. Then open the answer and compare it with yours.

  1. ExplainSay it in plain words in under a minute, with no notes.

    Explain State with the traffic-light picture.

    Show answer

    A traffic light reacts to the same event, "tick", differently depending on its colour: red goes to red-and-amber, green goes to amber, amber goes to red. Each colour knows what comes after it. You don't need one big rule book that says "if red and tick, then…, if green and tick, then…"; the current colour decides.

    The State pattern does this in code. An object (a vending machine) behaves differently in different situations (idle, has a coin, sold out). Instead of an if/elif on a status variable inside every method, each state is a class with a method for each event. The machine forwards each event to its current state object, and that state does the right thing and decides which state comes next. A new state is a new class, and each state's rules are in one place.

  2. DrawSketch the diagram (or class diagram) from memory.

    Draw the state diagram for an order: created, paid, shipped, delivered, cancelled, with the allowed transitions.

    Show answer

    Only the arrows shown are allowed; any other event in a state is refused with a clear message. An order can be cancelled before it ships (with a refund once paid); after shipping it is a return, not a cancellation. Delivered and cancelled are final.

    text
    created ──pay──► paid ──ship──► shipped ──deliver──► delivered
       │               │
       │ cancel        │ cancel (refund the payment)
       ▼               ▼
    cancelled ◄────────┘
    
    Final states: delivered, cancelled
    Refused, for example:
      ship   while created  (not paid yet)
      cancel while shipped  (use a return instead)
      pay    while cancelled
  3. ApplyUse it in a real design question and say exactly where it fits.

    Extend the vending machine below with a SoldOut state and a refund action.

    Show answer

    Every state now handles three events: insert_coin, press and refund. HasCoin.press() sells the snack, reduces the stock and moves to SoldOut if it was the last one, otherwise back to Idle. SoldOut refuses coins (handing them back) and presses. HasCoin.refund() returns the coin. The machine itself contains no if statements about its status: it just forwards each event to its current state.

    python
    class Idle:
        def insert_coin(self, machine):
            machine.state = HasCoin()
            return "coin accepted"
    
        def press(self, machine):
            return "insert a coin first"
    
        def refund(self, machine):
            return "no coin to return"
    
    
    class HasCoin:
        def insert_coin(self, machine):
            return "already has a coin"
    
        def press(self, machine):
            machine.stock -= 1
            machine.state = SoldOut() if machine.stock == 0 else Idle()
            return "here is your snack"
    
        def refund(self, machine):
            machine.state = Idle()
            return "coin returned"
    
    
    class SoldOut:
        def insert_coin(self, machine):
            return "sold out: coin returned"
    
        def press(self, machine):
            return "sold out"
    
        def refund(self, machine):
            return "no coin to return"
    
    
    class VendingMachine:
        def __init__(self, stock):
            self.stock = stock
            self.state = Idle() if stock > 0 else SoldOut()
    
        def insert_coin(self): return self.state.insert_coin(self)
        def press(self): return self.state.press(self)
        def refund(self): return self.state.refund(self)
    
    
    machine = VendingMachine(stock=1)
    for event in ["insert_coin", "refund", "insert_coin", "press", "insert_coin", "press"]:
        print(event, "→", getattr(machine, event)())
    # insert_coin → coin accepted
    # refund → coin returned
    # insert_coin → coin accepted
    # press → here is your snack
    # insert_coin → sold out: coin returned
    # press → sold out
  4. Trade-offsSay what it costs, when not to use it, and the alternative.

    State classes or a transition table (a dictionary of state → event → next state)?

    Show answer

    A transition table, a dictionary of state → event → next state (for example {"created": {"pay": "paid", "cancel": "cancelled"}, …}), is better when:
    • states mostly differ in which events are allowed and where they lead, not in what they do (an order's status, a ticket's workflow);
    • you want to see every transition at once, check it, draw it, or load it from configuration;
    • non-programmers need to read or change the rules.
    It is compact and data-driven, and any action can be looked up by name.

    State classes are better when:
    • each state really behaves differently (handling money, timers, different data), with real logic per event;
    • the behaviour per state keeps growing, and you want each state's code in one place, easy to test alone.
    The cost: the transitions are spread across classes, so the overall picture is harder to see.

    A common mix: a table for the allowed transitions, plus small functions or classes for the actions that run on each one.

Step 4 Interview-ready, then prove it

Your interview answer

About 20 to 40 seconds, said out loud. Practise it until it sounds like you, not like notes.

State moves each state's behaviour into its own class, so a vending machine or an order behaves correctly for its current state and the transitions are explicit, instead of an if/else on a status field in every method.

Follow-up questions

When is an enum and a switch enough?

When there are only a few states and events. The State pattern pays off as the states and rules grow.

Tick each check when you can do it without notes

A topic is finished when you pass all four checks, not when you finish a video. Be strict: if you needed your notes, it is not ticked yet.

  • Explain Say it in plain words in under a minute, with no notes.
  • Draw Sketch the diagram (or class diagram) from memory.
  • Apply Use it in a real design question and say exactly where it fits.
  • Trade-offs Say what it costs, when not to use it, and the alternative.

0 of 4 checks ticked.

Saved in this browser. Back it up or move it to another device.