State Pattern
Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.
Intent & Objective
Extract state-related behaviors into separate state classes. The original object delegates state-dependent work to an instance of a concrete state class instead of implementing massive conditional branches.
"Behavior changes automatically depending on current state (Red: Stop, Yellow: Prepare, Green: Go)."
"A person reacts very differently to the same situation depending on whether they are calm, joyful, or furious."
"Available buttons and actions change dynamically based on whether a card is inserted, PIN is verified, or cash is dispensing."
"A user story card changes rules and assignee as it moves from To Do -> In Progress -> Code Review -> Done."
The Problem
State machines written with giant `switch (state)` statements in every method. As new states are introduced, every single method in the class must be altered, causing regression bugs.
The Solution
Create new classes for all possible states of an object and extract all state-specific behaviors into these classes. Change the active state object at runtime.
Key Participants & Architectural Roles
Code Samples (Traditional OOP vs Functional Programming)
Available in C++, Python, and JavaParadigm Contrast: Traditional OOP vs Functional / Data-Oriented
In OOP, State is modeled via polymorphic classes mutating a context pointer. In Functional Programming, State is modeled as a Finite State Machine using Discriminated Unions / Algebraic Data Types, pure state transitions `(State, Event) -> State`, and Reducers (like Redux).
Advantages
- β Single Responsibility Principle: organizes the code related to particular states into separate classes
- β Open/Closed Principle: introduces new states without changing existing state classes or context
- β Eliminates bulky switch/case state machine conditionals
Trade-offs
- β Applying the pattern can be overkill if a state machine has only a few states and rarely changes
When to Apply
- β When you have an object that behaves differently depending on its current state, the number of states is enormous, and the state-specific code changes frequently
- β When you have a class polluted with massive conditionals that alter how the class fields behave
When to Avoid
- ! When the object has only 2 trivial boolean states (e.g. active / inactive)