メインコンテンツまでスキップ

🧩 State × Strategy

✅ 組み合わせの意図

  • 状態によって処理の可否や振る舞いを切り替えるために State パターンを使用し、
  • 実行する戦略(支払方法など)を柔軟に差し替えるために Strategy パターンを併用する

この組み合わせにより、状態遷移と処理内容の両方を分離・柔軟化できる。

✅ よく使われるシーン

  • 状態に応じて振る舞いを変えつつ、具体的な処理手段(アルゴリズム)も切り替えたい場合
  • 「現在は支払できる状態か?」「支払方法は何か?」という 2 つの軸があるようなシナリオ
  • 例:決済処理、会員ステータスに応じた機能制御、予約可否と処理手段の分離など

✅ UML クラス図

✅ コード例

interface PaymentStrategy {
pay(amount: number): void;
}

class CreditCardPayment implements PaymentStrategy {
pay(amount: number): void {
console.log(`[CreditCard] Paid ${amount}`);
}
}

class PayPalPayment implements PaymentStrategy {
pay(amount: number): void {
console.log(`[PayPal] Paid ${amount}`);
}
}

interface PaymentState {
handle(amount: number): void;
setStrategy(strategy: PaymentStrategy): void;
}

class ReadyState implements PaymentState {
constructor(private strategy: PaymentStrategy) {}

handle(amount: number): void {
console.log("Ready to process payment");
this.strategy.pay(amount);
}

setStrategy(strategy: PaymentStrategy): void {
this.strategy = strategy;
}
}

class DisabledState implements PaymentState {
handle(amount: number): void {
console.log("Payment is currently disabled");
}

setStrategy(strategy: PaymentStrategy): void {
console.log("Cannot set strategy while disabled");
}
}

class PaymentContext {
constructor(private state: PaymentState) {}

setState(state: PaymentState) {
this.state = state;
}

setStrategy(strategy: PaymentStrategy) {
this.state.setStrategy(strategy);
}

pay(amount: number) {
this.state.handle(amount);
}
}

// Usage
const context = new PaymentContext(new ReadyState(new CreditCardPayment()));
context.pay(100);

context.setStrategy(new PayPalPayment());
context.pay(200);

context.setState(new DisabledState());
context.pay(300);

✅ 解説

  • PaymentContext は現在の状態(PaymentState)を保持し、状態に応じた処理を委譲
  • ReadyStateDisabledStateState としての役割を果たし、handle メソッドの振る舞いを状態ごとに変える
  • StrategyCreditCardPayment, PayPalPayment)は、支払方法の切り替えを担当
  • 実行フロー:
    • PaymentContextReadyState なら支払戦略を用いた処理が可能
    • DisabledState なら拒否される

✅ まとめ

  • State パターン により、処理の可否や状態遷移のロジックを明確に分離
  • Strategy パターン により、可変な処理ロジック(支払方法など)を柔軟に切り替え可能
  • 状態と戦略の 2 軸がそれぞれ独立して拡張可能な、保守性の高い構造となる