0 XP · 0 scenes

State

An object changes its behaviour when its state changes
The problem

Every method begins with if state == "no_coin": ... elif state == "has_coin": ... The same state checks are repeated in each method.

The idea

Make each state a small class with the methods for that state.

Reach for it when

An object behaves differently in each of several states

1

The picture from life

A vending machine acts differently depending on whether a coin is inside. Press the button with no coin: "insert a coin". Press it with a coin: the snack drops. Same button, different behaviour, because the machine is in a different state.

2

The problem

What goes wrong when you do not use it.

Every method begins with if state == "no_coin": ... elif state == "has_coin": ... The same state checks are repeated in each method. Adding a "sold out" state means editing every method and risking a missed branch.

✗ Before
Machinepush(): if state == 'no_coin': ... elif state == 'has_coin': ...insert_coin(): if state == 'no_coin': ... elif state == 'has_coin': ...
Every method repeats the same big if/elif on the current state. A new state edits every method.
Reach for it when
  • An object behaves differently in each of several states
  • Big if/switch blocks test the same state variable
  • States have clear transitions (traffic light, order status)
3

The idea

How the pattern fixes it.

Make each state a small class with the methods for that state. The machine keeps a pointer to the current state object and forwards calls to it. A state changes the pointer to move to the next state.

✓ After
Machinestateinsert_coin()push()«interface»Stateinsert_coin(m)push(m)NoCoinHasCoincurrent stateinsert_coin
  • implements
  • has a / holds
  • calls / uses
Each state is a class that knows its own behaviour and the next state. The machine just forwards.

Who is who

Machine (context)
Holds the current state and forwards calls.
NoCoin, HasCoin
One class per state with its own behaviour.
Transitions
A state sets machine.state to the next state.

Build it in steps

  1. 1List the states and the events.
  2. 2Write a class per state with a method per event.
  3. 3Let the context hold and forward to the current state.
  4. 4Make each method return or set the next state.
4

Watch it run

Step through the calls. Tap an arrow to jump to it.

ClientMachineNoCoinHasCoin1push()2push(machine)3'insert a coin first'4insert_coin()5state = HasCoin()6push()7push(machine)8'here is your snack'
Step 1/8

The machine starts in NoCoin.

push()
5

The code

Python and Java. Try writing the classes yourself from the diagram first.

class NoCoin:
    def insert_coin(self, machine):
        machine.state = HasCoin()                    # move to the next state
        return "coin accepted"

    def push(self, machine):
        return "insert a coin first"


class HasCoin:
    def insert_coin(self, machine):
        return "coin already inserted"

    def push(self, machine):
        machine.state = NoCoin()
        return "here is your snack"


class Machine:
    def __init__(self):
        self.state = NoCoin()

    def insert_coin(self):
        return self.state.insert_coin(self)          # forward to the current state

    def push(self):
        return self.state.push(self)


def demo():
    m = Machine()
    return [m.push(), m.insert_coin(), m.insert_coin(), m.push(), m.push()]

What you gain

  • Each state's rules live in one class
  • New states do not touch the old ones

What it costs

  • More classes for a machine with few states
  • Transitions are spread across state classes

You have already met it in

  • Order lifecycle (placed, paid, shipped)
  • TCP connection states
  • Media players: playing, paused, stopped

Often mixed up with

  • StrategyStrategy: the caller picks an algorithm. State: the object moves itself between behaviours as it runs.
  • CommandCommand packages an action; State packages behaviour that depends on a mode.
6

Make it stick

Model a traffic light with Red, Green and Yellow states, each deciding its next state and how long it lasts.

Confidence