Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Design Patterns (GoF and modern)  Module 5 – Behavioral patterns: state and communication

State: behaviour that changes with state

State lets an object change its behaviour when its internal state changes. A vending machine as state classes, an enum with match and a transition table.

  • Intermediate
  • 30 minutes
  • Examples run with Python 3.14.8, Pyodide 314.0.7, Node.js 24.21.0, Java 25, Go 1.27.1, Clang 21.0.0 and Rust 1.99.0
  • By MySmartCoPilot
Free intro, Pro: 8 of 30 minutes free
Free: How State works. With a pass: the other 10 sections and 3 interview answers, about 22 minutes.

What you will learn

  • Implement a state machine with state objects, then with enums and pattern matching
  • Decide where transitions live, in the context, in the state objects or in a table
  • Test every edge of the state diagram, illegal transitions included
  • Recognise when a flat state machine needs hierarchical states (statecharts)

Before you start

What you’ll learn · Before you start

What you will learn

  • Implement a state machine with state objects, then with enums and pattern matching
  • Decide where transitions live, in the context, in the state objects or in a table
  • Test every edge of the state diagram, illegal transitions included
  • Recognise when a flat state machine needs hierarchical states (statecharts)

Before you start

On this page

State is a behavioural design pattern for an object whose behaviour depends on the situation it is in. Instead of checking a status flag in every method, the object keeps a current state, and each state decides what every event does: which events it accepts, which it refuses and which state comes next. When an event moves the object to a new state, its behaviour changes with it, so from the outside the object seems to change its class. Vending machines, order lifecycles, network connections, document workflows and the modes of an editor are all state machines.

How State works

A vending machine shows the problem. It can be idle, holding money, dispensing or sold out, and the same coin means different things in each: it starts a purchase when idle and must be refused while an item is being dispensed. Code that stores a status string and checks it with if statements in every method spreads each state across all the methods, so adding a state means editing every one of them, and a forgotten check silently accepts an event that should have been refused.

The State pattern puts each state’s behaviour in one place and makes every transition explicit. The machine’s states and transitions, drawn straight from its transition table:

State diagram of a vending machine: idle, has money, dispensing and sold out, joined by coin, choose, refund, done and restock.idlehas moneydispensingsold outcoinrestockrefundchoosedone [items left]done [none left]restock

The vending machine, drawn from its transition table

Text description of the diagram

Four states are drawn as boxes: idle, has money, dispensing and sold out. Arrows between them are the transitions, each labelled with the event that causes it.

  • From idle, "coin" leads to has money, and "restock" loops back to idle.
  • From has money, "refund" leads back to idle, and "choose" leads to dispensing.
  • From dispensing, "done" leads to idle when items are left, and to sold out when none are left. The two conditions in square brackets are guards.
  • From sold out, "restock" leads back to idle.

Any event not drawn from a state, such as "coin" while dispensing, is refused in that state. The diagram's source is generated from the same transition table the code uses.

The shortest correct implementation is that table, as data. The machine looks up its current state and the event; an entry gives the next state, and a missing entry means the event is refused in that state:

A vending machine driven by a transition table Python · table/vending.py
"""State as a transition table: the machine's current state decides what each event does, and an event the table
has no entry for is refused."""

# (state, event) -> next state, or a function of the machine when the next state depends on its data (a guard)
TRANSITIONS = {
    ("idle", "coin"): "has money",
    ("idle", "restock"): "idle",
    ("has money", "refund"): "idle",
    ("has money", "choose"): "dispensing",
    ("dispensing", "done"): lambda machine: "idle" if machine.stock else "sold out",
    ("sold out", "restock"): "idle",
}


class VendingMachine:
    def __init__(self, stock):
        self.state = "idle"
        self.stock = stock

    def handle(self, event):
        target = TRANSITIONS.get((self.state, event))
        if target is None:
            return f"{event:8} refused in {self.state}"
        if event == "choose":
            self.stock -= 1
        elif event == "restock":
            self.stock += 3
        before, self.state = self.state, target(self) if callable(target) else target
        return f"{event:8} {before} -> {self.state} (stock {self.stock})"


machine = VendingMachine(stock=1)
for event in ["choose", "coin", "choose", "coin", "done", "coin", "restock", "coin", "refund"]:
    print(machine.handle(event))

Output

choose   refused in idle
coin     idle -> has money (stock 1)
choose   has money -> dispensing (stock 0)
coin     refused in dispensing
done     dispensing -> sold out (stock 0)
coin     refused in sold out
restock  sold out -> idle (stock 3)
coin     idle -> has money (stock 3)
refund   has money -> idle (stock 3)

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 vending.py

The first “choose” is refused because nothing has been paid. After the only item is sold, “done” leads to sold out instead of idle: that entry is a guard, a condition on the machine’s data that decides between two next states. In sold out every coin is refused until a restock.

State machines are written in a few standard ways, and each has a name:

  • State classes give each state its own class with a method per event, the form in the Gang of Four catalogue.
  • An enum with match keeps the states as values and handles every state and event in one function.
  • A transition table lists each state and event with its next state, as data that is easy to draw and test.
  • Typestate gives each state its own type, so that an illegal transition does not even compile.
  • Statecharts add nested and parallel states to machines whose flat diagrams would explode.

Three implementations, tested by one matrix Pro: opens with a Pro, Premium or Ultimate pass

In this part:

  • Where the transitions live
  • Testing every edge, including the refused ones
  • A diagram drawn from the table
  • The same machine in six languages
  • When a flat machine needs a statechart
  • State or Strategy?
  • Exercise: an order lifecycle
    • An order lifecycle with guarded transitions and repeat-safe events
  • Check yourself
  • Interview questions
    • How is the State pattern different from the Strategy pattern?
    • An order's status is a string column, and code all over the service checks it with if statements before changing it. About twice a week an order is shipped after it was cancelled. How do you find the cause, and how do you redesign the lifecycle so that it cannot happen again?
    • A payment flow is a state machine with 12 states and 9 events. How do you test it so that every legal and illegal transition is covered, duplicate events are safe, and the diagram in the documentation can never disagree with the code?
    • A media player's state machine has stopped, playing and paused. Product wants a lockable screen, a mute switch and an offline mode, each independent of the others and of playback, and a "power off" that works from anywhere. Count what a flat machine needs, and redesign it.
  • Key takeaways

5 runnable examples (C++, Go, Java, Python, Rust, TypeScript, languages_session.py, session.py) · 1 exercise with sample tests · 3 interview answers · about 21 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.