State Pattern¶
Category: Behavioral Pattern
Overview¶
Allow an object to alter its behavior when its internal state changes, making the object appear to change its class. This pattern encapsulates state-specific behavior into separate state objects and delegates state-dependent behavior to the current state object.
Usage Guidelines¶
Use when:
- Object behavior changes based on internal state
- Multiple conditional statements based on state exist
- Clear state transitions exist between states
- State-specific behavior should be encapsulated
Avoid when:
- Object has only 2-3 simple states
- States don't change or transitions are trivial
- State-dependent behavior is minimal
- Pattern adds unnecessary complexity
Implementation¶
from __future__ import annotations
from abc import ABC, abstractmethod
class State(ABC):
"""Abstract base class for states."""
@abstractmethod
def publish(self, document: Document) -> str:
"""Attempt to publish the document."""
pass
@abstractmethod
def approve(self, document: Document) -> str:
"""Attempt to approve the document."""
pass
@abstractmethod
def get_status(self) -> str:
"""Get the current status name."""
pass
class DraftState(State):
"""State representing a draft document."""
def publish(self, document: Document) -> str:
"""Move document to moderation."""
document.set_state(ModerationState())
return "Document sent for moderation"
def approve(self, document: Document) -> str:
"""Cannot approve a draft."""
return "Cannot approve a draft document"
def get_status(self) -> str:
"""Get status name."""
return "Draft"
class ModerationState(State):
"""State representing a document under moderation."""
def publish(self, document: Document) -> str:
"""Already in moderation."""
return "Document is already in moderation"
def approve(self, document: Document) -> str:
"""Approve and publish the document."""
document.set_state(PublishedState())
return "Document approved and published"
def get_status(self) -> str:
"""Get status name."""
return "Moderation"
class PublishedState(State):
"""State representing a published document."""
def publish(self, document: Document) -> str:
"""Already published."""
return "Document is already published"
def approve(self, document: Document) -> str:
"""Already published."""
return "Document is already published"
def get_status(self) -> str:
"""Get status name."""
return "Published"
class Document:
"""Context class that maintains a state and delegates behavior to it."""
def __init__(self) -> None:
"""Initialize document in draft state."""
self._state: State = DraftState()
def set_state(self, state: State) -> None:
"""Set the current state."""
self._state = state
def publish(self) -> str:
"""Publish the document."""
return self._state.publish(self)
def approve(self) -> str:
"""Approve the document."""
return self._state.approve(self)
def get_status(self) -> str:
"""Get current document status."""
return self._state.get_status()
Usage¶
# Document workflow
doc = Document()
print(doc.get_status()) # Draft
result = doc.publish()
print(result) # Document sent for moderation
print(doc.get_status()) # Moderation
result = doc.approve()
print(result) # Document approved and published
print(doc.get_status()) # Published
Trade-offs¶
Benefits:
- State-specific behavior is encapsulated in state classes
- Each state class has single responsibility
- Easy to add new states without modifying context (Open/Closed Principle)
- Eliminates complex conditional logic
Drawbacks:
- Creates many state classes increasing code volume
- Can be overkill for simple state machines
- Managing transitions can become complex
- State object creation and switching adds overhead
Real-World Examples¶
- Document workflows with draft, review, published states
- TCP connections with closed, listening, established states
- Vending machines with idle, coin inserted, dispensing states
- Order processing with pending, confirmed, shipped states
Related Patterns¶
- Strategy
- Singleton
- Flyweight
- Memento
API Reference¶
design_patterns.behavioral.state
¶
State Pattern Module
The State pattern allows an object to alter its behavior when its internal state changes. The object will appear to change its class. This pattern encapsulates state-specific behavior into separate state objects and delegates state-dependent behavior to the current state object.
Example
Document workflow with different states:
Document
¶
Context class that maintains a state and delegates behavior to it.
Source code in src/design_patterns/behavioral/state.py
__init__()
¶
approve()
¶
Approve the document.
Returns:
| Type | Description |
|---|---|
str
|
Result message from current state. |
get_status()
¶
publish()
¶
Publish the document.
Returns:
| Type | Description |
|---|---|
str
|
Result message from current state. |
reject()
¶
DraftState
¶
Bases: State
State representing a draft document.
Source code in src/design_patterns/behavioral/state.py
approve(document)
¶
Cannot approve a draft.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
document
|
Document
|
The document. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Error message. |
get_status()
¶
publish(document)
¶
Move document to moderation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
document
|
Document
|
The document to publish. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Success message. |
Source code in src/design_patterns/behavioral/state.py
GreenLightState
¶
Bases: TrafficLightState
Green light state.
Source code in src/design_patterns/behavioral/state.py
get_color()
¶
next(light)
¶
Change to yellow.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
light
|
TrafficLight
|
The traffic light. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Transition message. |
Source code in src/design_patterns/behavioral/state.py
ModerationState
¶
Bases: State
State representing a document under moderation.
Source code in src/design_patterns/behavioral/state.py
approve(document)
¶
Approve and publish the document.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
document
|
Document
|
The document to approve. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Success message. |
Source code in src/design_patterns/behavioral/state.py
get_status()
¶
publish(document)
¶
Already in moderation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
document
|
Document
|
The document. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Info message. |
PublishedState
¶
Bases: State
State representing a published document.
Source code in src/design_patterns/behavioral/state.py
approve(document)
¶
Already published.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
document
|
Document
|
The document. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Info message. |
get_status()
¶
publish(document)
¶
Already published.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
document
|
Document
|
The document. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Info message. |
RedLightState
¶
Bases: TrafficLightState
Red light state.
Source code in src/design_patterns/behavioral/state.py
get_color()
¶
next(light)
¶
Change to green.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
light
|
TrafficLight
|
The traffic light. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Transition message. |
State
¶
Bases: ABC
Abstract base class for states.
Source code in src/design_patterns/behavioral/state.py
approve(document)
abstractmethod
¶
Attempt to approve the document.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
document
|
Document
|
The document whose state is being managed. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Result message. |
get_status()
abstractmethod
¶
publish(document)
abstractmethod
¶
Attempt to publish the document.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
document
|
Document
|
The document whose state is being managed. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Result message. |
TrafficLight
¶
Another example using traffic light states.
Source code in src/design_patterns/behavioral/state.py
__init__()
¶
get_color()
¶
next()
¶
set_state(state)
¶
Set the current state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
TrafficLightState
|
The new state. |
required |
TrafficLightState
¶
Bases: ABC
Abstract base class for traffic light states.
Source code in src/design_patterns/behavioral/state.py
get_color()
abstractmethod
¶
next(light)
abstractmethod
¶
Move to next state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
light
|
TrafficLight
|
The traffic light. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Result message. |
YellowLightState
¶
Bases: TrafficLightState
Yellow light state.
Source code in src/design_patterns/behavioral/state.py
get_color()
¶
next(light)
¶
Change to red.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
light
|
TrafficLight
|
The traffic light. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Transition message. |