概要
State(ステート)パターンは、
オブジェクトの状態が変化するたびに、そのオブジェクトの振る舞いも変化するように構造化するパターンである。
条件分岐(if-elif
や switch-case
)を多用するコードを整理し、
状態ごとに明確なクラスを定義することで、状態遷移と振る舞いの責務を分離し、保守性と拡張性を高める。
1. なぜStateパターンが必要か?
❌ 状態管理を条件分岐で処理
if self.state == "draft":
self.save_as_draft()
elif self.state == "published":
self.publish()
→ 状態が増えるごとに分岐が膨張し、メンテナンス困難に
✅ 各状態をクラスとして独立定義
post.set_state(DraftState())
post.save() # 状態オブジェクトに処理を委譲
→ 振る舞いの委譲により、ロジックを状態ごとに分離可能
2. 基本構造
✅ 状態インタフェース
class State:
def save(self, context):
raise NotImplementedError
✅ 状態の具象クラス
class DraftState(State):
def save(self, context):
print("Saving as draft...")
class PublishedState(State):
def save(self, context):
print("Already published. No save needed.")
✅ コンテキストクラス(状態保持者)
class Post:
def __init__(self):
self._state = DraftState()
def set_state(self, state):
self._state = state
def save(self):
self._state.save(self)
✅ 使用例
post = Post()
post.save() # → Saving as draft...
post.set_state(PublishedState())
post.save() # → Already published. No save needed.
3. Python的応用:動的遷移・イベントベース設計
class ApprovedState(State):
def save(self, context):
print("Cannot save. This is already approved.")
context.set_state(ArchivedState())
class ArchivedState(State):
def save(self, context):
print("Archived. Read-only.")
→ 状態が内部で他の状態へ自律的に遷移できる
4. 実務ユースケース
✅ コンテンツ管理システムの投稿状態管理
- Draft / Review / Published / Archived などの状態ごとの動作を分離
✅ UIコンポーネントのモード遷移(例:ボタン)
-
enabled
,disabled
,hovered
,pressed
状態ごとのビヘイビアを状態クラスで制御
✅ ゲーム内キャラクターの状態管理
-
idle
,running
,attacking
,damaged
のような行動状態に応じた処理の切替
✅ フロー制御、ワークフローのステップ管理
- 承認・却下・差し戻しなどを、状態クラスとして明示的に定義
5. よくある誤用と対策
❌ コンテキストクラスが状態ごとの振る舞いを保持してしまう
→ ✅ 各状態に処理を完全に委譲し、コンテキストはただの受け皿に徹する
❌ 状態クラスがコンテキストに依存しすぎる
→ ✅ 状態は独立した振る舞い定義に徹し、遷移や副作用のみ必要に応じて利用
❌ 状態が増えたときのクラス爆発
→ ✅ 状態を抽象化・再利用可能に設計し、DRY原則を意識
結語
Stateパターンとは、“状態による振る舞いの変化を設計上の構造で明示する”ためのパターンである。
- 分岐ロジックを状態クラスに分離し、高凝集・低結合な設計を実現
- 状態の増減に耐えうる柔軟性を備え、コードのスケーラビリティを向上
- Pythonの動的性とシンプルな構文が、Stateパターンの実装をより直感的にしてくれる
Pythonicとは、“動的な変化を構造で整理する”ことであり、
Stateパターンはその整理された変化の設計を、柔軟性と拡張性の核に据える技法である。