State Pattern

The state pattern is closely related to the concept of a finite state machine. Here's an example. [1]

Advantages

Step by Step

  1. identify the context: determine the class that has behavior that varies according to it's state. This class is known as the Context
class Context:
	def __init__(self, state: State):
		self._state = state
	def set_state(self, state: State):
		self._state = State
	def request(self):
		self._state.handler(self)
  1. define the state interface: create an interface or abstract class to represent the different states and encapsulate the behavior associated with each state.
  2. create concrete state classes: implement the state interface in a set of classes that represent the different states of the context object.
from abc import ABC, abstractmethod

class State(ABC):
	@abstractmethod
	def handle(self, context):
		pass

class ConcreteStateA(State):
	def handle(self, context):
		print('handling in the context of ConcreteStateA, transitioning to ConcreteStateB')
		context.set_state(ConcreteStateB())

class ConcreteStateB(State):
	def handle(self, context):
		print('handling in the context of ConcreteStateB, transitioning to ConcreteStateA')
		context.set_state(ConcreteStateA())
  1. link state and context: the context class maintains a reference to the current state.
  2. transition between states: to change to state, the context class will switch the current state object to a different subclass of the state interface. This can triggered by the context itself or by the state objects by giving them the ability to switch the context current state.
  3. use the pattern: the client interacts with the context class. when a state dependent actions is requested, the context delegates the request to the current state object, which handles it's according to it's implemented behavior
# start with state A
context = Context(ConcreteStateA())

# make a request, which should transition to state B
context.request()

# make another request, which should transition back to state A
context.request()
Use the state pattern when you have an object that behaves differently depending on it's current state, the number of states is enormous, and the state-specific code change frequently.

The pattern suggests that you extract all state-specific code into a set of distinct classes. as a result, you can add new states or change existing independently of each other, reducing the maintenance cost.

Use the pattern when you have a class polluted with massive conditionals that alter how the class behaves according to the current values of the class's field.

the state pattern lets you extract branches or these conditionals into methods of corresponding state classes. While doing so, you can also clean temporary fields and helper methods involves in state-specific code out of your main class.


  1. https://refactoring.guru/design-patterns/state ↩︎