---
# System prepended metadata

title: State Pattern Example
tags: [Python, CMSC23, OOP, Notes]

---

# State Pattern

### Problem

Some objects can change into many different states. If different objects behavior is dependent on its current state, it would require, bulky and annoying if-else blocks to handle its dynamic behavior.

![State](https://raw.githubusercontent.com/HowDoIGitHelp/CMSC23MDNotes/master/Markdown%20Lecture%20Notes%20and%20Lab%20Exercises/copyright%20free%20drawings/State.png)

### Solution

An object that can have many states should contain an attribute representing its state. Instead of performing, state dependent behavior directly inside the object, you delegate this responsibility to its embedded state instead. In this way the object will behave according to its current state.

![state pattern](https://raw.githubusercontent.com/HowDoIGitHelp/CMSC23MDNotes/master/Markdown%20Lecture%20Notes%20and%20Lab%20Exercises/uml/state.png)

The state may be required to contain backreference to the context object that owns it. This is only required if state methods requires to access/control the context that owns it.

![state diagram](https://raw.githubusercontent.com/HowDoIGitHelp/CMSC23MDNotes/master/Markdown%20Lecture%20Notes%20and%20Lab%20Exercises/uml/statediagram.png)

```python=
from abc import ABC,abstractmethod

class State(ABC):
    @abstractmethod
    def contextRelatedMethod(self):
        pass
    @abstractmethod
    def anotherContextRelatedMethod(self):
        pass
    @abstractmethod
    def stateName(self):
        pass

class InitialState(State):
    def __init__(self,context:'Context'):
        self.__context = context #this attribute is present only if you need a backreference to the context (if there are manipulations to context)
    def contextRelatedMethod(self):
        print("manipulating the context on initial state\nchanging to another state") #state methods may or may not change the state of the context this one does
        self.__context.changeState(AnotherState(self.__context))
    def anotherContextRelatedMethod(self):
        print("manipulating the context on initial state\nno changes in state")
    def stateName(self):
        return "Initial State"

class AnotherState(State):
    def __init__(self,context:'Context'):
        self.__context = context
    def contextRelatedMethod(self):
        print("manipulating the context on another state\nno changes in state")
    def anotherContextRelatedMethod(self):
        print("manipulating the context on another state\nchanging to initial state")
        self.__context.changeState(InitialState(self.__context))
    def stateName(self):
        return "Another State"

class Context:
    def __init__(self):
        self.__currentState = InitialState(self)
    def changeState(self,nextState:State):
        self.__currentState = nextState
    def method(self):
        self.__currentState.contextRelatedMethod() #delegation of behavior to attribute __currentState
    def anotherMethod(self):
        self.__currentState.anotherContextRelatedMethod() #delegation of behavior to attribute __currentState
    def display(self):
        print("context:")
        print("current state:" + self.__currentState.stateName())

c =  Context()
c.display()
print()
c.method()
print()
c.anotherMethod()
print()
c.method()
print()
c.method()
print()
c.display()

```