第05回: Strategyパターン — if文の連鎖を「差し替え可能な設計」に変える

章: 第1章: オブジェクト指向の深化

「処理の種類が増えるたびにif文が増える」問題

ソートアルゴリズムを切り替えたい、送信方法を切り替えたい、価格計算ルールを切り替えたい——。こうした「処理を差し替えたい」要求は実務で頻繁に起きます。

多くの場合、最初は if ($type === '...') で解決します。しかし種類が増えるたびに条件分岐が肥大化し、新しい処理の追加が既存コードへの変更を強制します。

Strategyパターンは「処理のアルゴリズム」をクラスとして表現し、呼び出し元を一切変えずに処理を差し替えられる設計です。

Strategyパターンの実装


<?php
// インターフェイス(戦略の契約)
interface SortStrategy {
    public function sort(array &$data): void;
}

// 具体的な戦略クラス
class BubbleSort implements SortStrategy {
    public function sort(array &$data): void {
        // バブルソートの実装
    }
}
class QuickSort implements SortStrategy {
    public function sort(array &$data): void {
        // クイックソートの実装
    }
}

// コンテキスト(戦略を使う側)
class Sorter {
    public function __construct(private SortStrategy $strategy) {}
    public function run(array &$data): void {
        $this->strategy->sort($data);
    }
}

// 使い方:処理を差し替えるだけ
$sorter = new Sorter(new QuickSort());
$sorter->run($data);

if文 vs Strategyパターン


<?php
// NG: 種類が増えるたびにここを変更しなければならない
function sendNotification(string $type, string $message): void {
    if ($type === 'email') {
        // メール送信
    } elseif ($type === 'slack') {
        // Slack送信
    } elseif ($type === 'sms') {
        // SMS送信(新規追加するたびにこのメソッドを変更)
    }
}

// OK: 新しい通知手段はクラスを追加するだけ
interface NotificationStrategy {
    public function send(string $message): void;
}
class EmailNotification implements NotificationStrategy { /* ... */ }
class SlackNotification implements NotificationStrategy { /* ... */ }
class SmsNotification implements NotificationStrategy { /* ... */ }
観点 if文のアプローチ Strategyパターン
新しい処理の追加 既存の分岐ブロックを変更 新クラスを追加するだけ
単体テスト 全分岐をまとめてテスト 各戦略クラスを独立してテスト
コードの読みやすさ 種類が増えるほど複雑化 クラス名が処理の意図を表す

チェックポイント: if ($type === ...)switch ($type) が3種類以上になってきたら、Strategyパターンへの切り出しを検討しましょう。

実務での使いどころ

  • 支払い方法(クレジット、銀行振込、コンビニ払い)の切り替え
  • ファイル出力形式(CSV、JSON、XML)の切り替え
  • バリデーションルールの組み合わせ
  • キャッシュドライバーの切り替え

まとめ & 次のステップ

  • Strategyパターンはアルゴリズムをクラスに閉じ込め、呼び出し元を変えずに差し替えを可能にする
  • if文の連鎖が増えてきたら、インターフェイスを定義して戦略クラスに切り出すのがサイン
  • DIと組み合わせることで、コンストラクタで戦略を注入する設計が実現できる

次回はObserverパターンを学びます。「何かが起きたら複数の処理を動かす」仕組みを、発行側のコードを変えずに実現する方法です。

Related Articles