🧩 State パターン
✅ 設計意図
- オブジェクトの状態をクラスとして表現し、状態ごとに処理を定義
- 現在の状態がそのまま「振る舞いの選択」に直結
✅ 適用理由
- 状態ごとの処理をクラス分けして責任分離できる
- 状態遷移のルールも状態自身が知っているため、制御が明確
✅ 向いているシーン
- ステップ処理、状態遷移、モード切り替えなどの UI や業務フロー
- 状態が増える可能性が高く、将来的に拡張が想定される
✅ コード例
- TypeScript
- PHP
- Python
// 状態インターフェース
interface DocumentState {
publish(context: DocumentContext): void;
}
// 状態クラス(draft)
class DraftState implements DocumentState {
publish(context: DocumentContext): void {
console.log("レビュー依頼を送信");
context.setState(new ReviewState());
}
}
// 状態クラス(review)
class ReviewState implements DocumentState {
publish(context: DocumentContext): void {
console.log("公開しました");
context.setState(new PublishedState());
}
}
// 状態クラス(published)
class PublishedState implements DocumentState {
publish(context: DocumentContext): void {
console.log("すでに公開済みです");
}
}
// コンテキスト
class DocumentContext {
private state: DocumentState;
constructor() {
this.state = new DraftState();
}
setState(state: DocumentState): void {
this.state = state;
}
publish(): void {
this.state.publish(this);
}
}
// 利用例
const doc = new DocumentContext();
doc.publish(); // → レビュー依頼
doc.publish(); // → 公開
doc.publish(); // → すでに公開済み
<?php
interface DocumentState {
public function publish(DocumentContext $context): void;
}
class DraftState implements DocumentState {
public function publish(DocumentContext $context): void {
echo "レビュー依頼を送信\n";
$context->setState(new ReviewState());
}
}
class ReviewState implements DocumentState {
public function publish(DocumentContext $context): void {
echo "公開しました\n";
$context->setState(new PublishedState());
}
}
class PublishedState implements DocumentState {
public function publish(DocumentContext $context): void {
echo "すでに公開済みです\n";
}
}
class DocumentContext {
private DocumentState $state;
public function __construct() {
$this->state = new DraftState();
}
public function setState(DocumentState $state): void {
$this->state = $state;
}
public function publish(): void {
$this->state->publish($this);
}
}
// 利用例
$doc = new DocumentContext();
$doc->publish(); // → レビュー依頼
$doc->publish(); // → 公開
$doc->publish(); // → すでに公開済み
from abc import ABC, abstractmethod
class DocumentState(ABC):
@abstractmethod
def publish(self, context: "DocumentContext"):
pass
class DraftState(DocumentState):
def publish(self, context: "DocumentContext"):
print("レビュー依頼を送信")
context.set_state(ReviewState())
class ReviewState(DocumentState):
def publish(self, context: "DocumentContext"):
print("公開しました")
context.set_state(PublishedState())
class PublishedState(DocumentState):
def publish(self, context: "DocumentContext"):
print("すでに公開済みです")
class DocumentContext:
def __init__(self):
self._state: DocumentState = DraftState()
def set_state(self, state: DocumentState):
self._state = state
def publish(self):
self._state.publish(self)
# 利用例
doc = DocumentContext()
doc.publish() # → レビュー依頼
doc.publish() # → 公開
doc.publish() # → すでに公開済み
✅ 解説
このコードは State
パターン を使用して、ドキュメントの状態(Draft
, Review
, Published
)に応じた振る舞いを切り替える設計を実現している。State
パターンは、オブジェクトの内部状態に応じて振る舞いを変更するデザインパターンであり、条件分岐を排除してコードの可読性と保守性を向上させる。
1. State パターンの概要
- State: 状態ごとの振る舞いを定義するインターフェース
- このコードでは
DocumentState
が該当
- このコードでは
- ConcreteState:
State
を実装し、具体的な状態ごとの振る舞いを提供するクラス- このコードでは
DraftState
,ReviewState
,PublishedState
が該当
- このコードでは
- Context: 現在の状態を保持し、状態に応じた振る舞いを委譲するクラス
- このコードでは
DocumentContext
が該当
- このコードでは
2. 主なクラスとその役割
DocumentState
- 状態の共通インターフェース
publish(context: DocumentContext): void
メソッドを定義
DraftState
ConcreteState
クラス- ドキュメントが「下書き」状態の場合の振る舞いを定義
publish
メソッドで「レビュー依頼を送信」し、状態をReviewState
に遷移
ReviewState
ConcreteState
クラス- ドキュメントが「レビュー中」状態の場合の振る舞いを定義
publish
メソッドで「公開」し、状態をPublishedState
に遷移
PublishedState
ConcreteState
クラス- ドキュメントが「公開済み」状態の場合の振る舞いを定義
publish
メソッドで「すでに公開済みです」と出力
DocumentContext
Context
クラス- 現在の状態を保持し、
publish
メソッドで現在の状態に応じた振る舞いを実行 - 状態遷移は
setState
メソッドで管理
3. UML クラス図
4. State パターンの利点
- 条件分岐の排除: 状態ごとの処理をクラスに分離することで、条件分岐を排除。
- 拡張性: 新しい状態を追加する場合も、
DocumentState
を実装するだけで対応可能。 - 動的な状態切り替え: 実行時に状態を簡単に切り替え可能。
この設計は、状態に応じた振る舞いを明確に分離し、状態遷移を安全に管理する。特に、状態が複数あり、それぞれの振る舞いが異なる場合に有効に機能する。