
Stan w języku Python
Stan to behawioralny wzorzec projektowy pozwalający zmieniać zachowanie obiektu w odpowiedzi na zmianę jego wewnętrznego stanu.
Wzorzec Stan zakłada ekstrakcję zachowań odnoszących się do stanu obiektu do osobnych klas odpowiadających jego poszczególnym stanom. Pierwotny obiekt wówczas deleguje pracę instancjom tych klas, zamiast wykonywać ją samodzielnie.
Złożoność:
Popularność:
Przykłady użycia: Wzorzec Stan jest powszechnie stosowany w kodzie Python w celu konwersji obszernych maszyn stanów opartych na instrukcji switch
w obiekty.
Identyfikacja: Wzorzec Stan można poznać po obecności metod zmieniających swoje zachowanie zależnie od stanu obiektu, sterowanego z zewnątrz.
Przykład koncepcyjny
Poniższy przykład ilustruje strukturę wzorca Stan ze szczególnym naciskiem na następujące kwestie:
- Z jakich składa się klas?
- Jakie role pełnią te klasy?
- W jaki sposób elementy wzorca są ze sobą powiązane?
main.py: Przykład koncepcyjny
from __future__ import annotations
from abc import ABC, abstractmethod
class Context:
"""
The Context defines the interface of interest to clients. It also maintains
a reference to an instance of a State subclass, which represents the current
state of the Context.
"""
_state = None
"""
A reference to the current state of the Context.
"""
def __init__(self, state: State) -> None:
self.transition_to(state)
def transition_to(self, state: State):
"""
The Context allows changing the State object at runtime.
"""
print(f"Context: Transition to {type(state).__name__}")
self._state = state
self._state.context = self
"""
The Context delegates part of its behavior to the current State object.
"""
def request1(self):
self._state.handle1()
def request2(self):
self._state.handle2()
class State(ABC):
"""
The base State class declares methods that all Concrete State should
implement and also provides a backreference to the Context object,
associated with the State. This backreference can be used by States to
transition the Context to another State.
"""
@property
def context(self) -> Context:
return self._context
@context.setter
def context(self, context: Context) -> None:
self._context = context
@abstractmethod
def handle1(self) -> None:
pass
@abstractmethod
def handle2(self) -> None:
pass
"""
Concrete States implement various behaviors, associated with a state of the
Context.
"""
class ConcreteStateA(State):
def handle1(self) -> None:
print("ConcreteStateA handles request1.")
print("ConcreteStateA wants to change the state of the context.")
self.context.transition_to(ConcreteStateB())
def handle2(self) -> None:
print("ConcreteStateA handles request2.")
class ConcreteStateB(State):
def handle1(self) -> None:
print("ConcreteStateB handles request1.")
def handle2(self) -> None:
print("ConcreteStateB handles request2.")
print("ConcreteStateB wants to change the state of the context.")
self.context.transition_to(ConcreteStateA())
if __name__ == "__main__":
# The client code.
context = Context(ConcreteStateA())
context.request1()
context.request2()
Output.txt: Wynik działania
Context: Transition to ConcreteStateA
ConcreteStateA handles request1.
ConcreteStateA wants to change the state of the context.
Context: Transition to ConcreteStateB
ConcreteStateB handles request2.
ConcreteStateB wants to change the state of the context.
Context: Transition to ConcreteStateA