![State](/images/patterns/cards/state-mini.png?id=f4018837e0641d1dade756b6678fd4ee)
State を Python で
State は、 振る舞いに関するデザインパターンの一つで、 オブジェクトの内部状態が変化した時にその振る舞いを変更することを可能とします。
このパターンは、 状態に関連した振る舞いを個別の状態のクラスへ抽出し、 元のオブジェクトが作業を自分で行わず、 これらのクラスのインスタンスに委任することを強制します。
複雑度:
人気度:
使用例: Python では、 State パターンは、 膨大な数の switch
文に基づく状態機械をオブジェクトに変換する時によく使われます。
見つけ方: オブジェクトが、 その外的に制御される状態によって振る舞いを変えるようなメソッドを持っていたら、 State パターンを識別できます。
概念的な例
この例は、 State デザインパターンの構造を説明するためのものです。 以下の質問に答えることを目的としています:
- どういうクラスからできているか?
- それぞれのクラスの役割は?
- パターンの要素同士はどう関係しているのか?
main.py: 概念的な例
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: 実行結果
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