ステートパターンは、オブジェクトの内部状態が変化することによって、そのオブジェクトの振る舞いが変わることを表現するためのデザインパターンです。このパターンを使うことで、状態に応じた振る舞いを分離し、状態を持つクラスをより簡潔に管理できます。
ここでは、簡単な音楽プレイヤーの状態管理を例にとります。音楽プレイヤーは「再生中」「一時停止中」「停止中」の3つの状態を持ちます。
まず、状態を表すインターフェース State
を定義します。
from abc import ABC, abstractmethod
class State(ABC):
@abstractmethod
def play(self, player):
pass
@abstractmethod
def pause(self, player):
pass
@abstractmethod
def stop(self, player):
pass
次に、具体的な状態クラスを実装します。
class PlayingState(State):
def play(self, player):
print("すでに再生中です。")
def pause(self, player):
print("一時停止します。")
player.set_state(PausedState())
def stop(self, player):
print("停止します。")
player.set_state(StoppedState())
class PausedState(State):
def play(self, player):
print("再生再開します。")
player.set_state(PlayingState())
def pause(self, player):
print("すでに一時停止中です。")
def stop(self, player):
print("停止します。")
player.set_state(StoppedState())
class StoppedState(State):
def play(self, player):
print("再生します。")
player.set_state(PlayingState())
def pause(self, player):
print("停止中のため、一時停止できません。")
def stop(self, player):
print("すでに停止中です。")
最後に、音楽プレイヤーを表すコンテキストクラス MusicPlayer
を定義します。
class MusicPlayer:
def __init__(self):
self.state = StoppedState() # 初期状態は停止中
def set_state(self, state):
self.state = state
def play(self):
self.state.play(self)
def pause(self):
self.state.pause(self)
def stop(self):
self.state.stop(self)
以下のコードを実行して、音楽プレイヤーの状態遷移を確認します。
if __name__ == "__main__":
player = MusicPlayer()
# 状態の遷移を試す
player.play() # 再生します。
player.pause() # 一時停止します。
player.stop() # 停止します。
player.stop() # すでに停止中です。
player.play() # 再生します。
player.pause() # 一時停止します。
player.play() # 再生再開します。
State
):これは、すべての具体的な状態クラスが実装しなければならないメソッドを定義します。
具体的な状態クラス (PlayingState
, PausedState
, StoppedState
):
各状態に特有の振る舞いを実装します。たとえば、再生中に再生メソッドを呼ぶと、再生中のメッセージが表示されますが、一時停止メソッドで状態を変更します。
コンテキストクラス (MusicPlayer
):
このように、ステートパターンを用いることで、状態ごとの振る舞いを明確に分離し、コードの可読性と保守性を向上させることができます。