🧩 State パターン
✅ 設計意図
- 「注文の状態(未確定 / 確定)」や「処理モード」によって振る舞いを切り替えたい
- 状態ごとにクラスを分けて、処理ロジックを状態オブジェクト側に任せる
✅ 適用理由
OrderManager
が「状態に応じて異なる振る舞いをする」機能を持っていた- 状態遷移の明示性・安全性を上げる
✅ 向いているシーン
- ステップごとの処理(ウィザード式など)
- 処理の状態ごとに分岐がある
✅ コード例
- TypeScript
- PHP
- Python
interface OrderState {
confirm(order: StatefulOrderProcessor): void;
}
class UnconfirmedState implements OrderState {
confirm(order: StatefulOrderProcessor): void {
// 在庫調整・メール送信など
InventoryService.reduce(order.productIds);
EmailService.send(order.userEmail, "注文が確定されました");
OrderLogger.log("order-" + Math.random().toString(36).substring(2));
order.setState(new ConfirmedState());
}
}
class ConfirmedState implements OrderState {
confirm(order: StatefulOrderProcessor): void {
console.log("すでに確定済みです");
}
}
class StatefulOrderProcessor {
private state: OrderState;
constructor(public productIds: string[], public userEmail: string) {
this.state = new UnconfirmedState();
}
setState(state: OrderState) {
this.state = state;
}
confirmOrder() {
this.state.confirm(this);
}
}
// 利用例
const stateProcessor = new StatefulOrderProcessor(
["p01", "p02"],
"hiroshi@example.com"
);
stateProcessor.confirmOrder(); // 初回 → 確定
stateProcessor.confirmOrder(); // 2回目 → 確定済みメッセージ
<?php
interface OrderState {
public function confirm(StatefulOrderProcessor $order): void;
}
class UnconfirmedState implements OrderState {
public function confirm(StatefulOrderProcessor $order): void {
InventoryService::reduce($order->productIds);
EmailService::send($order->userEmail, "注文が確定されました");
OrderLogger::log("order-" . substr(md5((string)mt_rand()), 0, 8));
$order->setState(new ConfirmedState());
}
}
class ConfirmedState implements OrderState {
public function confirm(StatefulOrderProcessor $order): void {
echo "すでに確定済みです\\n";
}
}
class StatefulOrderProcessor {
public OrderState $state;
public array $productIds;
public string $userEmail;
public function __construct(array $productIds, string $userEmail) {
$this->productIds = $productIds;
$this->userEmail = $userEmail;
$this->state = new UnconfirmedState();
}
public function setState(OrderState $state): void {
$this->state = $state;
}
public function confirmOrder(): void {
$this->state->confirm($this);
}
}
// 外部サービス(ダミー)
class InventoryService {
public static function reduce(array $productIds): void {
echo "在庫を " . count($productIds) . " 件分減らしました\\n";
}
}
class EmailService {
public static function send(string $email, string $message): void {
echo "メールを {$email} に送信: {$message}\\n";
}
}
class OrderLogger {
public static function log(string $orderId): void {
echo "注文ログを記録: {$orderId}\\n";
}
}
// 利用例
$processor = new StatefulOrderProcessor(["p01", "p02"], "hiroshi@example.com");
$processor->confirmOrder(); // 初回:確定
$processor->confirmOrder(); // 2回目:すでに確定済み
import random
import string
from abc import ABC, abstractmethod
# 状態インターフェース
class OrderState(ABC):
@abstractmethod
def confirm(self, order: "StatefulOrderProcessor"):
pass
# 状態クラス:未確定
class UnconfirmedState(OrderState):
def confirm(self, order: "StatefulOrderProcessor"):
InventoryService.reduce(order.product_ids)
EmailService.send(order.user_email, "注文が確定されました")
order_id = "order-" + ''.join(random.choices(string.ascii_lowercase + string.digits, k=8))
OrderLogger.log(order_id)
order.set_state(ConfirmedState())
# 状態クラス:確定済み
class ConfirmedState(OrderState):
def confirm(self, order: "StatefulOrderProcessor"):
print("すでに確定済みです")
# コンテキスト
class StatefulOrderProcessor:
def __init__(self, product_ids: list[str], user_email: str):
self.product_ids = product_ids
self.user_email = user_email
self.state: OrderState = UnconfirmedState()
def set_state(self, state: OrderState):
self.state = state
def confirm_order(self):
self.state.confirm(self)
# 外部サービス(ダミー)
class InventoryService:
@staticmethod
def reduce(product_ids: list[str]):
print(f"在庫を {len(product_ids)} 件分減らしました")
class EmailService:
@staticmethod
def send(email: str, message: str):
print(f"メールを {email} に送信: {message}")
class OrderLogger:
@staticmethod
def log(order_id: str):
print(f"注文ログを記録: {order_id}")
# 利用例
processor = StatefulOrderProcessor(["p01", "p02"], "hiroshi@example.com")
processor.confirm_order() # 初回:確定
processor.confirm_order() # 2回目:すでに確定済み
✅ 解説
このコードは State
パターン を使用して、注文処理の状態(未確定・確定済み)に応じた振る舞いを切り替える設計を実現している
State
パターンは、オブジェクトの内部状態に応じて振る舞いを変更するデザインパターンであり、
状態ごとの処理をクラスとして分離し、状態遷移を明示的に管理する
1. State パターンの概要
- このコードでは、
OrderState
インターフェースを基に、以下の状態クラスを実装している:UnconfirmedState
: 注文が未確定の状態ConfirmedState
: 注文が確定済みの状態
2. 主なクラスとその役割
OrderState
インターフェース- 状態ごとの振る舞いを定義するインターフェース
confirm(order: StatefulOrderProcessor): void
メソッドを実装する必要がある
UnconfirmedState
- 注文が未確定の状態を表すクラス
confirm
メソッドで以下の処理を行う:- 在庫を減らす
- ユーザーにメールを送信
- 注文ログを記録
- 状態を
ConfirmedState
に遷移
ConfirmedState
- 注文が確定済みの状態を表すクラス
confirm
メソッドでは「すでに確定済みです」というメッセージを出力する
StatefulOrderProcessor
- 状態を管理するコンテキストクラス
- 現在の状態を保持し、
confirmOrder
メソッドを呼び出すことで現在の状態に応じた処理を実行する - 状態遷移は setState メソッドで行う
3. UML クラス図
4. State パターンの利点
- 状態ごとの振る舞いを分離: 各状態の処理が独立しているため、コードが読みやすく保守性が高い
- 状態遷移が明示的: 状態の変更が
setState
メソッドで管理されるため、状態遷移が分かりやすい - 拡張性: 新しい状態を追加する場合も、
OrderState
を実装するだけで対応可能
この設計は、状態に応じた振る舞いを明確に分離し、状態遷移を安全に管理する。