概要
State(ステート)パターンは、
オブジェクトの内部状態によって振る舞いを動的に切り替えるための設計パターンである。
状態ごとにロジックを分離することで、条件分岐の煩雑さを回避しつつ、保守性・拡張性を担保できる。
状態遷移を明示的な設計要素として捉える構造である。
1. なぜStateが必要か?
❌ if文・switch文による状態分岐が増えすぎると、コードが肥大化・複雑化する
def handle():
if state == "idle":
...
elif state == "running":
...
elif state == "paused":
...
→ 状態と振る舞いが密結合となり、拡張に弱くなる
✅ 各状態をクラスとして分離し、状態に応じた振る舞いをオブジェクトに委譲
state = IdleState()
state.handle(context)
→ ロジックが状態ごとに独立し、構造的に拡張・切替が可能
2. 基本構造
✅ Stateインターフェース
class State:
def handle(self, context):
raise NotImplementedError
✅ Context(状態管理対象)
class Context:
def __init__(self):
self.state: State = IdleState()
def set_state(self, state: State):
print(f"[状態遷移] {type(self.state).__name__} → {type(state).__name__}")
self.state = state
def request(self):
self.state.handle(self)
✅ ConcreteState(具体的な状態)
class IdleState(State):
def handle(self, context):
print("待機中。実行を開始します。")
context.set_state(RunningState())
class RunningState(State):
def handle(self, context):
print("実行中。ポーズします。")
context.set_state(PausedState())
class PausedState(State):
def handle(self, context):
print("一時停止中。再開します。")
context.set_state(RunningState())
✅ 使用例
ctx = Context()
ctx.request() # Idle → Running
ctx.request() # Running → Paused
ctx.request() # Paused → Running
出力:
待機中。実行を開始します。
[状態遷移] IdleState → RunningState
実行中。ポーズします。
[状態遷移] RunningState → PausedState
一時停止中。再開します。
[状態遷移] PausedState → RunningState
3. Python的応用:辞書による状態遷移定義
transitions = {
"idle": "running",
"running": "paused",
"paused": "running"
}
state = "idle"
for _ in range(4):
print(f"現在の状態: {state}")
state = transitions[state]
→ 軽量なユースケースでは辞書でもState的な挙動を表現可能
4. 実務ユースケース
✅ UIコンポーネントの状態管理(表示/非表示/無効など)
→ 状態ごとのロジック切り替えをクラス化・分離可能
✅ ゲーム内キャラクターの状態管理(待機/移動/攻撃/死亡)
→ 行動制御を状態単位で整理
✅ ワークフロー・処理ステータスの管理
→ 例:申請→承認→完了 などの業務フロー
✅ サーバ・通信接続状態(接続/切断/リトライ)
→ 各ネットワーク状態に応じた処理分岐を疎結合化
5. よくある誤用と対策
❌ Contextが状態ごとの処理を再び内包してしまう
→ ✅ 処理はすべてStateクラスに委譲する設計に徹する
❌ 状態遷移が不明瞭で、どこからどこに遷移可能か分からない
→ ✅ 状態遷移図を明確にし、コメントやドキュメントで整理
❌ 状態数が増えすぎて、クラス数が爆発する
→ ✅ 状態の粒度を設計段階で適切に見極め、統合すべきものはまとめる
結語
Stateパターンとは、“振る舞いを状態として構造化し、オブジェクトの動的な変化に知性を与える設計”である。
- 条件分岐を構造化し、状態による処理の違いを安全かつ明示的に表現
- 状態数が多くても、各クラスが独立しテストしやすく、保守性が高い
- Pythonでは動的に状態を切り替え、柔軟なコンテキスト制御が可能
Pythonicとは、“状態を見て振る舞いを変えるのではなく、状態に振る舞わせること”。
Stateパターンはその動的な知性を、オブジェクトの構造として昇華する技法である。