Skip to content

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:

  1. State-specific behavior is encapsulated in state classes
  2. Each state class has single responsibility
  3. Easy to add new states without modifying context (Open/Closed Principle)
  4. Eliminates complex conditional logic

Drawbacks:

  1. Creates many state classes increasing code volume
  2. Can be overkill for simple state machines
  3. Managing transitions can become complex
  4. 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
  • 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:

doc = Document()
print(doc.get_status())  # "Draft"

doc.publish()
print(doc.get_status())  # "Moderation"

doc.approve()
print(doc.get_status())  # "Published"

Document

Context class that maintains a state and delegates behavior to it.

Source code in src/design_patterns/behavioral/state.py
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.

        Args:
            state: The new state.
        """
        self._state = state

    def publish(self) -> str:
        """Publish the document.

        Returns:
            Result message from current state.
        """
        return self._state.publish(self)

    def approve(self) -> str:
        """Approve the document.

        Returns:
            Result message from current state.
        """
        return self._state.approve(self)

    def reject(self) -> str:
        """Reject the document.

        Returns:
            Result message from current state.
        """
        return self._state.reject(self)

    def get_status(self) -> str:
        """Get current document status.

        Returns:
            Current status string.
        """
        return self._state.get_status()

__init__()

Initialize document in draft state.

Source code in src/design_patterns/behavioral/state.py
def __init__(self) -> None:
    """Initialize document in draft state."""
    self._state: State = DraftState()

approve()

Approve the document.

Returns:

Type Description
str

Result message from current state.

Source code in src/design_patterns/behavioral/state.py
def approve(self) -> str:
    """Approve the document.

    Returns:
        Result message from current state.
    """
    return self._state.approve(self)

get_status()

Get current document status.

Returns:

Type Description
str

Current status string.

Source code in src/design_patterns/behavioral/state.py
def get_status(self) -> str:
    """Get current document status.

    Returns:
        Current status string.
    """
    return self._state.get_status()

publish()

Publish the document.

Returns:

Type Description
str

Result message from current state.

Source code in src/design_patterns/behavioral/state.py
def publish(self) -> str:
    """Publish the document.

    Returns:
        Result message from current state.
    """
    return self._state.publish(self)

reject()

Reject the document.

Returns:

Type Description
str

Result message from current state.

Source code in src/design_patterns/behavioral/state.py
def reject(self) -> str:
    """Reject the document.

    Returns:
        Result message from current state.
    """
    return self._state.reject(self)

set_state(state)

Set the current state.

Parameters:

Name Type Description Default
state State

The new state.

required
Source code in src/design_patterns/behavioral/state.py
def set_state(self, state: State) -> None:
    """Set the current state.

    Args:
        state: The new state.
    """
    self._state = state

DraftState

Bases: State

State representing a draft document.

Source code in src/design_patterns/behavioral/state.py
class DraftState(State):
    """State representing a draft document."""

    def publish(self, document: Document) -> str:
        """Move document to moderation.

        Args:
            document: The document to publish.

        Returns:
            Success message.
        """
        document.set_state(ModerationState())
        return "Document sent for moderation"

    def approve(self, document: Document) -> str:
        """Cannot approve a draft.

        Args:
            document: The document.

        Returns:
            Error message.
        """
        return "Cannot approve a draft document"

    def reject(self, document: Document) -> str:
        """Cannot reject a draft.

        Args:
            document: The document.

        Returns:
            Error message.
        """
        return "Cannot reject a draft document"

    def get_status(self) -> str:
        """Get status name.

        Returns:
            Status string.
        """
        return "Draft"

approve(document)

Cannot approve a draft.

Parameters:

Name Type Description Default
document Document

The document.

required

Returns:

Type Description
str

Error message.

Source code in src/design_patterns/behavioral/state.py
def approve(self, document: Document) -> str:
    """Cannot approve a draft.

    Args:
        document: The document.

    Returns:
        Error message.
    """
    return "Cannot approve a draft document"

get_status()

Get status name.

Returns:

Type Description
str

Status string.

Source code in src/design_patterns/behavioral/state.py
def get_status(self) -> str:
    """Get status name.

    Returns:
        Status string.
    """
    return "Draft"

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
def publish(self, document: Document) -> str:
    """Move document to moderation.

    Args:
        document: The document to publish.

    Returns:
        Success message.
    """
    document.set_state(ModerationState())
    return "Document sent for moderation"

reject(document)

Cannot reject a draft.

Parameters:

Name Type Description Default
document Document

The document.

required

Returns:

Type Description
str

Error message.

Source code in src/design_patterns/behavioral/state.py
def reject(self, document: Document) -> str:
    """Cannot reject a draft.

    Args:
        document: The document.

    Returns:
        Error message.
    """
    return "Cannot reject a draft document"

GreenLightState

Bases: TrafficLightState

Green light state.

Source code in src/design_patterns/behavioral/state.py
class GreenLightState(TrafficLightState):
    """Green light state."""

    def next(self, light: TrafficLight) -> str:
        """Change to yellow.

        Args:
            light: The traffic light.

        Returns:
            Transition message.
        """
        light.set_state(YellowLightState())
        return "Changed from Green to Yellow"

    def get_color(self) -> str:
        """Get color.

        Returns:
            Green.
        """
        return "Green"

get_color()

Get color.

Returns:

Type Description
str

Green.

Source code in src/design_patterns/behavioral/state.py
def get_color(self) -> str:
    """Get color.

    Returns:
        Green.
    """
    return "Green"

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
def next(self, light: TrafficLight) -> str:
    """Change to yellow.

    Args:
        light: The traffic light.

    Returns:
        Transition message.
    """
    light.set_state(YellowLightState())
    return "Changed from Green to Yellow"

ModerationState

Bases: State

State representing a document under moderation.

Source code in src/design_patterns/behavioral/state.py
class ModerationState(State):
    """State representing a document under moderation."""

    def publish(self, document: Document) -> str:
        """Already in moderation.

        Args:
            document: The document.

        Returns:
            Info message.
        """
        return "Document is already in moderation"

    def approve(self, document: Document) -> str:
        """Approve and publish the document.

        Args:
            document: The document to approve.

        Returns:
            Success message.
        """
        document.set_state(PublishedState())
        return "Document approved and published"

    def reject(self, document: Document) -> str:
        """Reject and return to draft.

        Args:
            document: The document to reject.

        Returns:
            Success message.
        """
        document.set_state(DraftState())
        return "Document rejected, returned to draft"

    def get_status(self) -> str:
        """Get status name.

        Returns:
            Status string.
        """
        return "Moderation"

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
def approve(self, document: Document) -> str:
    """Approve and publish the document.

    Args:
        document: The document to approve.

    Returns:
        Success message.
    """
    document.set_state(PublishedState())
    return "Document approved and published"

get_status()

Get status name.

Returns:

Type Description
str

Status string.

Source code in src/design_patterns/behavioral/state.py
def get_status(self) -> str:
    """Get status name.

    Returns:
        Status string.
    """
    return "Moderation"

publish(document)

Already in moderation.

Parameters:

Name Type Description Default
document Document

The document.

required

Returns:

Type Description
str

Info message.

Source code in src/design_patterns/behavioral/state.py
def publish(self, document: Document) -> str:
    """Already in moderation.

    Args:
        document: The document.

    Returns:
        Info message.
    """
    return "Document is already in moderation"

reject(document)

Reject and return to draft.

Parameters:

Name Type Description Default
document Document

The document to reject.

required

Returns:

Type Description
str

Success message.

Source code in src/design_patterns/behavioral/state.py
def reject(self, document: Document) -> str:
    """Reject and return to draft.

    Args:
        document: The document to reject.

    Returns:
        Success message.
    """
    document.set_state(DraftState())
    return "Document rejected, returned to draft"

PublishedState

Bases: State

State representing a published document.

Source code in src/design_patterns/behavioral/state.py
class PublishedState(State):
    """State representing a published document."""

    def publish(self, document: Document) -> str:
        """Already published.

        Args:
            document: The document.

        Returns:
            Info message.
        """
        return "Document is already published"

    def approve(self, document: Document) -> str:
        """Already published.

        Args:
            document: The document.

        Returns:
            Info message.
        """
        return "Document is already published"

    def reject(self, document: Document) -> str:
        """Unpublish and return to draft.

        Args:
            document: The document to unpublish.

        Returns:
            Success message.
        """
        document.set_state(DraftState())
        return "Document unpublished, returned to draft"

    def get_status(self) -> str:
        """Get status name.

        Returns:
            Status string.
        """
        return "Published"

approve(document)

Already published.

Parameters:

Name Type Description Default
document Document

The document.

required

Returns:

Type Description
str

Info message.

Source code in src/design_patterns/behavioral/state.py
def approve(self, document: Document) -> str:
    """Already published.

    Args:
        document: The document.

    Returns:
        Info message.
    """
    return "Document is already published"

get_status()

Get status name.

Returns:

Type Description
str

Status string.

Source code in src/design_patterns/behavioral/state.py
def get_status(self) -> str:
    """Get status name.

    Returns:
        Status string.
    """
    return "Published"

publish(document)

Already published.

Parameters:

Name Type Description Default
document Document

The document.

required

Returns:

Type Description
str

Info message.

Source code in src/design_patterns/behavioral/state.py
def publish(self, document: Document) -> str:
    """Already published.

    Args:
        document: The document.

    Returns:
        Info message.
    """
    return "Document is already published"

reject(document)

Unpublish and return to draft.

Parameters:

Name Type Description Default
document Document

The document to unpublish.

required

Returns:

Type Description
str

Success message.

Source code in src/design_patterns/behavioral/state.py
def reject(self, document: Document) -> str:
    """Unpublish and return to draft.

    Args:
        document: The document to unpublish.

    Returns:
        Success message.
    """
    document.set_state(DraftState())
    return "Document unpublished, returned to draft"

RedLightState

Bases: TrafficLightState

Red light state.

Source code in src/design_patterns/behavioral/state.py
class RedLightState(TrafficLightState):
    """Red light state."""

    def next(self, light: TrafficLight) -> str:
        """Change to green.

        Args:
            light: The traffic light.

        Returns:
            Transition message.
        """
        light.set_state(GreenLightState())
        return "Changed from Red to Green"

    def get_color(self) -> str:
        """Get color.

        Returns:
            Red.
        """
        return "Red"

get_color()

Get color.

Returns:

Type Description
str

Red.

Source code in src/design_patterns/behavioral/state.py
def get_color(self) -> str:
    """Get color.

    Returns:
        Red.
    """
    return "Red"

next(light)

Change to green.

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
def next(self, light: TrafficLight) -> str:
    """Change to green.

    Args:
        light: The traffic light.

    Returns:
        Transition message.
    """
    light.set_state(GreenLightState())
    return "Changed from Red to Green"

State

Bases: ABC

Abstract base class for states.

Source code in src/design_patterns/behavioral/state.py
class State(ABC):
    """Abstract base class for states."""

    @abstractmethod
    def publish(self, document: Document) -> str:
        """Attempt to publish the document.

        Args:
            document: The document whose state is being managed.

        Returns:
            Result message.
        """
        pass

    @abstractmethod
    def approve(self, document: Document) -> str:
        """Attempt to approve the document.

        Args:
            document: The document whose state is being managed.

        Returns:
            Result message.
        """
        pass

    @abstractmethod
    def reject(self, document: Document) -> str:
        """Attempt to reject the document.

        Args:
            document: The document whose state is being managed.

        Returns:
            Result message.
        """
        pass

    @abstractmethod
    def get_status(self) -> str:
        """Get the current status name.

        Returns:
            Status string.
        """
        pass

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.

Source code in src/design_patterns/behavioral/state.py
@abstractmethod
def approve(self, document: Document) -> str:
    """Attempt to approve the document.

    Args:
        document: The document whose state is being managed.

    Returns:
        Result message.
    """
    pass

get_status() abstractmethod

Get the current status name.

Returns:

Type Description
str

Status string.

Source code in src/design_patterns/behavioral/state.py
@abstractmethod
def get_status(self) -> str:
    """Get the current status name.

    Returns:
        Status string.
    """
    pass

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.

Source code in src/design_patterns/behavioral/state.py
@abstractmethod
def publish(self, document: Document) -> str:
    """Attempt to publish the document.

    Args:
        document: The document whose state is being managed.

    Returns:
        Result message.
    """
    pass

reject(document) abstractmethod

Attempt to reject the document.

Parameters:

Name Type Description Default
document Document

The document whose state is being managed.

required

Returns:

Type Description
str

Result message.

Source code in src/design_patterns/behavioral/state.py
@abstractmethod
def reject(self, document: Document) -> str:
    """Attempt to reject the document.

    Args:
        document: The document whose state is being managed.

    Returns:
        Result message.
    """
    pass

TrafficLight

Another example using traffic light states.

Source code in src/design_patterns/behavioral/state.py
class TrafficLight:
    """Another example using traffic light states."""

    def __init__(self) -> None:
        """Initialize traffic light in red state."""
        self._state: TrafficLightState = RedLightState()

    def set_state(self, state: TrafficLightState) -> None:
        """Set the current state.

        Args:
            state: The new state.
        """
        self._state = state

    def next(self) -> str:
        """Move to next state.

        Returns:
            Result message.
        """
        return self._state.next(self)

    def get_color(self) -> str:
        """Get current light color.

        Returns:
            Color string.
        """
        return self._state.get_color()

__init__()

Initialize traffic light in red state.

Source code in src/design_patterns/behavioral/state.py
def __init__(self) -> None:
    """Initialize traffic light in red state."""
    self._state: TrafficLightState = RedLightState()

get_color()

Get current light color.

Returns:

Type Description
str

Color string.

Source code in src/design_patterns/behavioral/state.py
def get_color(self) -> str:
    """Get current light color.

    Returns:
        Color string.
    """
    return self._state.get_color()

next()

Move to next state.

Returns:

Type Description
str

Result message.

Source code in src/design_patterns/behavioral/state.py
def next(self) -> str:
    """Move to next state.

    Returns:
        Result message.
    """
    return self._state.next(self)

set_state(state)

Set the current state.

Parameters:

Name Type Description Default
state TrafficLightState

The new state.

required
Source code in src/design_patterns/behavioral/state.py
def set_state(self, state: TrafficLightState) -> None:
    """Set the current state.

    Args:
        state: The new state.
    """
    self._state = state

TrafficLightState

Bases: ABC

Abstract base class for traffic light states.

Source code in src/design_patterns/behavioral/state.py
class TrafficLightState(ABC):
    """Abstract base class for traffic light states."""

    @abstractmethod
    def next(self, light: TrafficLight) -> str:
        """Move to next state.

        Args:
            light: The traffic light.

        Returns:
            Result message.
        """
        pass

    @abstractmethod
    def get_color(self) -> str:
        """Get the color of this state.

        Returns:
            Color string.
        """
        pass

get_color() abstractmethod

Get the color of this state.

Returns:

Type Description
str

Color string.

Source code in src/design_patterns/behavioral/state.py
@abstractmethod
def get_color(self) -> str:
    """Get the color of this state.

    Returns:
        Color string.
    """
    pass

next(light) abstractmethod

Move to next state.

Parameters:

Name Type Description Default
light TrafficLight

The traffic light.

required

Returns:

Type Description
str

Result message.

Source code in src/design_patterns/behavioral/state.py
@abstractmethod
def next(self, light: TrafficLight) -> str:
    """Move to next state.

    Args:
        light: The traffic light.

    Returns:
        Result message.
    """
    pass

YellowLightState

Bases: TrafficLightState

Yellow light state.

Source code in src/design_patterns/behavioral/state.py
class YellowLightState(TrafficLightState):
    """Yellow light state."""

    def next(self, light: TrafficLight) -> str:
        """Change to red.

        Args:
            light: The traffic light.

        Returns:
            Transition message.
        """
        light.set_state(RedLightState())
        return "Changed from Yellow to Red"

    def get_color(self) -> str:
        """Get color.

        Returns:
            Yellow.
        """
        return "Yellow"

get_color()

Get color.

Returns:

Type Description
str

Yellow.

Source code in src/design_patterns/behavioral/state.py
def get_color(self) -> str:
    """Get color.

    Returns:
        Yellow.
    """
    return "Yellow"

next(light)

Change to red.

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
def next(self, light: TrafficLight) -> str:
    """Change to red.

    Args:
        light: The traffic light.

    Returns:
        Transition message.
    """
    light.set_state(RedLightState())
    return "Changed from Yellow to Red"