Pythonにおける状態パターン：状態遷移をオブジェクトに委譲する設計



## 概要

**状態パターン（State Pattern）**は、  
オブジェクトの内部状態に応じて、その振る舞い（メソッドの実装）を動的に切り替える設計手法。

状態をクラスとして独立させることで、**条件分岐の削減、状態遷移の明示、振る舞いの分離**が可能となり、  
複雑な状態管理を洗練された構造で実現できる。

本稿では、Pythonにおける状態パターンの実装と実務活用例を解説する。

---

## 1. なぜStateパターンが必要か？

### ❌ 状態に応じた if-else が膨張する構造

```python
if self.state == "draft":
    self.save_as_draft()
elif self.state == "submitted":
    self.submit_to_approval()
elif self.state == "approved":
    self.lock()
```

→ 状態が増えるたびに分岐が複雑化、保守困難に

---

### ✅ 状態ごとの振る舞いをクラスに分離

```python
class DraftState:
    def handle(self, context): ...

class ApprovedState:
    def handle(self, context): ...
```

→ **状態をオブジェクトとして設計することで、処理がスケーラブルに**

---

## 2. 基本構造

### ✅ 状態インタフェース

```python
class State:
    def submit(self, context): raise NotImplementedError
    def approve(self, context): raise NotImplementedError
```

---

### ✅ 具体的状態クラス

```python
class Draft(State):
    def submit(self, context):
        print("Submitted")
        context.set_state(Submitted())

    def approve(self, context):
        print("Cannot approve draft")

class Submitted(State):
    def submit(self, context):
        print("Already submitted")

    def approve(self, context):
        print("Approved")
        context.set_state(Approved())

class Approved(State):
    def submit(self, context):
        print("Already approved")

    def approve(self, context):
        print("Already approved")
```

---

### ✅ コンテキストクラス

```python
class Document:
    def __init__(self):
        self.state = Draft()

    def set_state(self, state):
        self.state = state

    def submit(self):
        self.state.submit(self)

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

---

### ✅ 実行例

```python
doc = Document()
doc.submit()   # → Submitted
doc.approve()  # → Approved
doc.approve()  # → Already approved
```

---

## 3. 状態パターンのメリット

- **状態ごとの処理が明確に分離**されるため、可読性と拡張性が高い
- 状態遷移のルールを**オブジェクトレベルで管理**できる
- if-else地獄を排除し、振る舞いを**構造としてモデル化**できる

---

## 4. 実務的ユースケース

### ✅ ワークフロー管理

- 「作成 → 提出 → 承認 → 完了」といった複雑な状態遷移を制御  
- 各状態における許可アクションをクラス内で定義し、**フローの正当性を担保**

---

### ✅ UIコンポーネントの状態制御

- ボタン：enabled / hovered / clicked / disabled
- 状態クラスを切り替えることで、**描画や振る舞いを一貫管理**

---

### ✅ ゲーム開発：プレイヤーのステート管理

- 例：Idle, Running, Attacking, Dying
- 各状態が `enter()`, `exit()`, `update()` を持ち、**状態マシンの構築が容易**

---

## 5. Python的に書きやすくする工夫

### ✅ EnumとStateクラスの併用

```python
from enum import Enum

class Status(Enum):
    DRAFT = "draft"
    SUBMITTED = "submitted"
    APPROVED = "approved"
```

→ 状態の識別子をEnumで定義し、Stateインスタンスとマッピング

---

### ✅ 状態テーブルで動的切替（簡易型）

```python
class StateMachine:
    def __init__(self):
        self.state = "draft"

    def transition(self, event):
        rules = {
            ("draft", "submit"): "submitted",
            ("submitted", "approve"): "approved"
        }
        self.state = rules.get((self.state, event), self.state)
```

→ 小規模なら状態テーブルで管理するパターンも選択肢に

---

## 6. よくある誤用と対策

### ❌ 状態を文字列や数値で持ち続ける

→ ✅ `State` クラスとして定義し、**振る舞いと状態を結合させる**

---

### ❌ 状態間の遷移ロジックをコンテキスト側に書く

→ ✅ 状態クラスが自身の遷移先を決定することで、**流れが一元化される**

---

## 結語

状態パターンは、**「条件分岐による振る舞いの切替」を「構造による振る舞いの委譲」に変換する設計手法**である。

- 状態の数が増えるほど、**構造化の恩恵が大きくなる**  
- 分岐の除去、可視性の向上、状態遷移の明示という、**実務的な設計課題に直結**  
- Pythonのクラスベース設計との親和性も高く、OOPの理解深化にも繋がる

**Pythonicとは、“条件を消し、構造で語る”ことであり、  
状態パターンはその哲学を実現するための洗練された形式である。**