状態遷移ロジックの集中
説明(どんな問題か)
どんな状態か?
- オブジェクトが持つ状態に応じて処理を変えたいが、状態と振る舞いが密結合
if
やswitch
文で状態ごとの処理を管理している- 状態が増えると処理が肥大化し、読みにくくなる
なぜ問題か?
- 状態が増えるたびに、既存コードを修正する必要がある(開閉原則違反)
- 責務が 1 クラスに集中して、テスト困難・可読性低下
- 将来的な拡張や状態遷移ロジックが煩雑になる
アンチパターンのコード例
- TypeScript
- PHP
- Python
class Document {
private state: string = "draft"; // 状態: 'draft', 'review', 'published'
publish() {
if (this.state === "draft") {
console.log("レビュー依頼を送信");
this.state = "review";
} else if (this.state === "review") {
console.log("公開しました");
this.state = "published";
} else if (this.state === "published") {
console.log("すでに公開済みです");
}
}
}
<?php
class Document {
private string $state = "draft"; // 状態: 'draft', 'review', 'published'
public function publish(): void {
if ($this->state === "draft") {
echo "レビュー依頼を送信\n";
$this->state = "review";
} elseif ($this->state === "review") {
echo "公開しました\n";
$this->state = "published";
} elseif ($this->state === "published") {
echo "すでに公開済みです\n";
}
}
}
class Document:
def __init__(self):
self.state = "draft" # 状態: 'draft', 'review', 'published'
def publish(self):
if self.state == "draft":
print("レビュー依頼を送信")
self.state = "review"
elif self.state == "review":
print("公開しました")
self.state = "published"
elif self.state == "published":
print("すでに公開済みです")
問題点:
- 状態が文字列で管理され、振る舞いも 1 クラスに集中
- 新しい状態が追加されるたびに
publish()
を修正する必要がある - 状態と処理が混在していて拡張に弱い
パターン別のリファクタリング
対応可能なデザインパターン例
パターン | 概要 | 主な解決アプローチ |
---|---|---|
State | 状態ごとにオブジェクトを分け、振る舞いを委譲 | 状態を明示的にクラスで管理 |
Strategy | 振る舞いを外部に差し替える | 状態を切り替える制御は外部任せ |
Command | 状態による処理をコマンドオブジェクトで持つ | 実行内容をオブジェクト化し柔軟に制御 |