State

状態パターンは、オブジェクトの内部状態が変化することでその振る舞いを変更することができるデザインパターンです。このパターンを使用すると、オブジェクトはランタイムにその状態を表す別のオブジェクトに委譲することができます。これにより、オブジェクトの振る舞いは状態によって変わり、多数の条件分岐を避けることができます。

使用シーン

状態パターンは以下のような場合に特に有用です:

  1. オブジェクトの振る舞いがその状態に依存しており、状態が多数存在する場合

    • オブジェクトが多くの異なる条件分岐を持つ複雑な状態マシンを実装しているときに適しています。

  2. 同じオブジェクトに対する操作が、そのオブジェクトの状態によって異なる結果をもたらす場合

    • オブジェクトの状態が変わると、同じメソッド呼び出しで異なる結果が得られることを意味します。

メリットとデメリット

メリット

  • 高い柔軟性:新しい状態クラスを追加することで、簡単に新しい状態と振る舞いを導入できます。

  • 状態の変更の集中化:状態に関連する振る舞いが各状態クラスに集中されるため、状態の管理が簡単になります。

  • 状態遷移の明確化:状態遷移を明示的なものにし、オブジェクトの状態管理を簡素化します。

デメリット

  • クラスの増加:状態ごとに新しいクラスが必要になるため、システムの複雑性が増します。

  • 依存関係:状態がお互いを知る必要がある場合、クラス間の依存関係が複雑になることがあります。

サンプルコード(Python)

以下は、文書のレビュープロセスを模倣した状態パターンの実装例です。

from abc import ABC, abstractmethod

class DocumentState(ABC):
    """文書の状態を表す抽象基底クラス"""

    @abstractmethod
    def approve(self):
        pass

    @abstractmethod
    def deny(self):
        pass

class DraftState(DocumentState):
    """下書き状態を表すクラス"""
    
    def approve(self):
        return ModerationState()

    def deny(self):
        return RejectedState()

class ModerationState(DocumentState):
    """審査中状態を表すクラス"""
    
    def approve(self):
        return ApprovedState()

    def deny(self):
        return RejectedState()

class ApprovedState(DocumentState):
    """承認状態を表すクラス"""

    def approve(self):
        return self

    def deny(self):
        return self

class RejectedState(DocumentState):
    """却下状態を表すクラス"""

    def approve(self):
        return self

    def deny(self):
        return self

class Document:
    """文書を表すクラス"""
    
    def __init__(self):
        self.state = DraftState()

    def approve(self):
        self.state = self.state.approve()

    def deny(self):
        self.state = self.state.deny()

# クライアントコード
document = Document()
print(type(document.state))  # DraftState

document.approve()
print(type(document.state))  # ModerationState

document.approve()
print(type(document.state))  # ApprovedState

document.deny()  # 承認状態からは変わらない
print(type(document.state))  # ApprovedState

この例では、Document クラスが文書を表し、その状態を DocumentState インターフェイスに準拠したいくつかの状態オブジェクトによって表現します。Document クラスの approvedeny メソッドは、現在の状態の同名のメソッドを呼び出すことによって、文書の状態を変更します。各状態オブジェクトは、状態遷移のロジックをカプセル化しており、文書が次の状態に移行するたびに新しい状態オブジェクトを返します。

状態パターンを異なるシナリオで適用する一例として、交通信号機の状態管理を考えてみましょう。信号機は「赤」「黄」「緑」という状態を持ち、各状態は特定の振る舞いと次の状態への遷移を持っています。

シナリオ: 交通信号機の状態管理

サンプルコード(Python)

from abc import ABC, abstractmethod
import time

class TrafficLightState(ABC):
    """交通信号機の状態を表す抽象基底クラス"""

    @abstractmethod
    def change(self, traffic_light):
        pass

    @abstractmethod
    def display(self):
        pass

class RedLightState(TrafficLightState):
    """赤信号の状態を表すクラス"""
    
    def change(self, traffic_light):
        traffic_light.state = GreenLightState()

    def display(self):
        print("RED - Cars should stop")

class YellowLightState(TrafficLightState):
    """黄信号の状態を表すクラス"""
    
    def change(self, traffic_light):
        traffic_light.state = RedLightState()

    def display(self):
        print("YELLOW - Cars should prepare to stop")

class GreenLightState(TrafficLightState):
    """緑信号の状態を表すクラス"""
    
    def change(self, traffic_light):
        traffic_light.state = YellowLightState()

    def display(self):
        print("GREEN - Cars can go")

class TrafficLight:
    """交通信号機を表すクラス"""
    
    def __init__(self):
        self.state = RedLightState()

    def change(self):
        self.state.change(self)

    def display(self):
        self.state.display()

# クライアントコード
traffic_light = TrafficLight()
traffic_light.display()  # 初期状態: 赤信号

# 信号機の状態を変更して表示
traffic_light.change()
traffic_light.display()  # 緑信号

traffic_light.change()
traffic_light.display()  # 黄信号

traffic_light.change()
traffic_light.display()  # 赤信号

このコード例では、TrafficLight クラスが信号機を表し、その状態は TrafficLightState というインターフェースを実装したいくつかの具体的な状態クラスによって表現されます。TrafficLight クラスの change メソッドは、現在の状態オブジェクトの change メソッドを呼び出すことによって、信号機の状態を次の状態に遷移させます。各状態オブジェクトは、信号の表示(display)と次の状態への遷移(change)のロジックをカプセル化しており、信号機の振る舞いを状態ごとに独立して管理できます。

この記事が気に入ったらサポートをしてみませんか?