<一覧に戻る

ステートパターン

ステートパターンは、オブジェクトの内部状態が変化することによって、そのオブジェクトの振る舞いが変わることを表現するためのデザインパターンです。このパターンを使うことで、状態に応じた振る舞いを分離し、状態を持つクラスをより簡潔に管理できます。

ステートパターンの基本概念

  • 状態(State): オブジェクトの状態を表すインターフェースまたは抽象クラス。
  • 具体的な状態(Concrete State): 状態を具現化したクラス。異なる状態に応じた具体的な振る舞いを定義します。
  • コンテキスト(Context): 現在の状態を持つオブジェクト。このオブジェクトは、状態の変更や状態に基づく振る舞いを管理します。

サンプルコード

ここでは、簡単な音楽プレイヤーの状態管理を例にとります。音楽プレイヤーは「再生中」「一時停止中」「停止中」の3つの状態を持ちます。

ステップ 1: 状態インターフェースの定義

まず、状態を表すインターフェース 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

ステップ 2: 具体的な状態の実装

次に、具体的な状態クラスを実装します。

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("すでに停止中です。")

ステップ 3: コンテキストクラスの実装

最後に、音楽プレイヤーを表すコンテキストクラス 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)

ステップ 4: 使用例

以下のコードを実行して、音楽プレイヤーの状態遷移を確認します。

if __name__ == "__main__":
    player = MusicPlayer()

    # 状態の遷移を試す
    player.play()  # 再生します。
    player.pause()  # 一時停止します。
    player.stop()   # 停止します。
    player.stop()   # すでに停止中です。
    player.play()   # 再生します。
    player.pause()  # 一時停止します。
    player.play()   # 再生再開します。

解説

  1. 状態インターフェース (State):
  2. これは、すべての具体的な状態クラスが実装しなければならないメソッドを定義します。

  3. 具体的な状態クラス (PlayingState, PausedState, StoppedState):

  4. 各状態に特有の振る舞いを実装します。たとえば、再生中に再生メソッドを呼ぶと、再生中のメッセージが表示されますが、一時停止メソッドで状態を変更します。

  5. コンテキストクラス (MusicPlayer):

  6. 現在の状態を保持し、状態に応じて適切なメソッドを呼び出します。

このように、ステートパターンを用いることで、状態ごとの振る舞いを明確に分離し、コードの可読性と保守性を向上させることができます。

出力結果: