Facebook Pixel

State Pattern

Scattered conditionals checking a status field

A turnstile has two states: locked and unlocked. It reacts to two events: a coin is inserted, or a person pushes through. In the naive implementation, both event handlers check the current state and branch on it:

1# Bad: every method must check self.state and branch.
2# Adding a third state (broken, maintenance) multiplies every method.
3class Turnstile:
4    def __init__(self) -> None:
5        self.state = "LOCKED"
6
7    def insert_coin(self) -> None:
8        if self.state == "LOCKED":
9            self.state = "UNLOCKED"
10            print("Coin accepted — turnstile unlocked.")
11        elif self.state == "UNLOCKED":
12            print("Already unlocked — coin returned.")
13
14    def push(self) -> None:
15        if self.state == "LOCKED":
16            print("Locked — please insert a coin.")
17        elif self.state == "UNLOCKED":
18            self.state = "LOCKED"
19            print("Passage granted — turnstile locked.")

The problem is structural. The state lives as a plain string, and every method has to enumerate every state it might be in — so the behavior of a single state, like what LOCKED does on each event, is smeared across multiple methods instead of gathered in one place. And the conditionals multiply as the machine grows: add a third state — say, a BROKEN state that ignores both events and displays an error — and every method grows another branch; a fourth multiplies the branching again. The total complexity grows as states × events.

How it works

The State pattern moves each state's behavior into its own class. The context (Turnstile) holds a reference to the current state object and delegates both events to it. Transitions are expressed by swapping the state object, not by mutating a string field.


The class structure mirrors the diagram: one class per state, each implementing the same two-method interface.


Adding a BrokenState means adding one class, not editing every existing method. The complexity of the code grows as states + events, not as states × events.

Tracing a coin-insert and then a push shows how the context delegates each event to the current state object, which handles it and swaps the context's state when a transition occurs.

Good: one class per state, context delegates

Invest in Yourself
Your new job is waiting. 83% of people that complete the program get a job offer. Unlock unlimited access to all content and features.
Go Pro