State Pattern in Python

Sean Bradley
Design Patterns In Python
3 min readMar 3, 2021

--

Not to be confused with object state, i.e., one of more attributes that can be copied as a snapshot, the State Pattern is more concerned about changing the handle of an object’s method dynamically. This makes an object itself more dynamic and may reduce the need of many conditional statements.

Instead of storing a value in an attribute, and then then using conditional statements within an objects method to produce different output, a subclass is assigned as a handle instead. The object/context doesn’t need to know about the inner working of the assigned subclass that the task was delegated to.

In the state pattern, the behaviour of an objects state is encapsulated within the subclasses that are dynamically assigned to handle it.

Terminology

  • State Interface: An interface for encapsulating the behaviour associated with a particular state of the Context.
  • Concrete Subclasses: Each subclass implements a behaviour associated with the particular state.
  • Context: This is the object where the state is defined, but the execution of the state behaviour is redirected to the concrete subclass.

State Pattern UML Diagram

State Pattern UML Diagram

Source Code

In the concept example, there are three possible states. Every time the request() method is called, the concrete state subclass is randomly selected by the context.

./state/state_concept.py

"""
The State Pattern Concept
https://sbcode.net/python/state/#statestate_conceptpy
"""
from abc import ABCMeta, abstractmethod
import random
class Context():
"This is the object whose behavior will change"
def __init__(self):
self.state_handles = [ConcreteStateA(),
ConcreteStateB(),
ConcreteStateC()]
self.handle = None
def request(self):
"""
A method of the state that dynamically changes which
class it uses depending on the value of self.handle
"""
self.handle = self.state_handles[random.randint(0, 2)]
return self.handle
class IState(metaclass=ABCMeta):
"A State Interface"
@staticmethod
@abstractmethod
def __str__():
"Set the default method"
class ConcreteStateA(IState):
"A ConcreteState Subclass"
def __str__(self):
return "I am ConcreteStateA"
class ConcreteStateB(IState):
"A ConcreteState Subclass"
def __str__(self):
return "I am ConcreteStateB"
class ConcreteStateC(IState):
"A ConcreteState Subclass"
def __str__(self):
return "I am ConcreteStateC"
# The Client
CONTEXT = Context()
print(CONTEXT.request())
print(CONTEXT.request())
print(CONTEXT.request())
print(CONTEXT.request())
print(CONTEXT.request())

Output

python.exe ./state/state_concept.py
I am ConcreteStateB
I am ConcreteStateA
I am ConcreteStateB
I am ConcreteStateA
I am ConcreteStateC

Video of the State Pattern

State Example Use Case

Visit State — Design Patterns In Python (sbcode.net) for an example use case of using the State pattern.

This example use case takes the above concept example further and uses an iterator rather than choosing the states subclasses randomly.

When the iterator gets to the end, it raises a StopIteration error and recreates the iterator so that the process can loop again.

Video of a State Pattern use case

Summary

  • Makes an object change its behaviour when its internal state changes.
  • The client and the context are not concerned about the details of how the state is created/assembled/calculated. The client will call a method of the context and it will be handled by a subclass.
  • The State pattern appears very similar to the Strategy pattern, except in the State pattern, the object/context has changed to a different state and will run a different subclass depending on that state.

Thanks for reading my article on the Interpreter pattern. For more design patterns please visit my series on Design Patterns in Python at https://medium.com/design-patterns-in-python

Sean

Design Patterns In Python (Book)

You can also buy this series in paperback.
Book provides FREE access to online instructional videos.
Design Patterns In Python : ASIN B08XLJ8Z2J

--

--

Sean Bradley
Design Patterns In Python

Developer of real time, low latency, high availability, asynchronous, multi threaded, remotely managed, fully automated and monitored solutions.