# 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() ```