🎉

デザインパターンを学ぶ #16 チェーン・オブ・リスポンシビリティ(Chain of Responsibility)

に公開

1. はじめに

今回は Chain of Responsibility(責任の連鎖)パターン
目的は、複数の処理担当者をチェーン状につなぎ、リクエストを順番に渡していく仕組みを作ることです。

典型的な用途は ログ処理・イベント処理・バリデーションなど、
「どの担当が処理するか分からないけど、とりあえず流してみて適切な担当が対応する」ような場合です。

2. Chain of Responsibilityとは?

責任の連鎖パターンでは、リクエストを処理する複数のハンドラ(処理役)を直列に並べて、処理できる人が対応するまで順番に渡すという考え方を取ります。

主な登場役は以下の2つです:

  • Handler(処理役) … リクエストを処理できるか判定し、処理できなければ次に渡す
  • ConcreteHandler(具体的な処理役) … 実際の処理を担当するクラス(例:ログ処理、権限チェックなど)

3. 実装イメージ(PHP)

<?php
// Handler 抽象クラス
abstract class Handler {
    private ?Handler $next = null;

    public function setNext(Handler $next): Handler {
        $this->next = $next;
        return $next;
    }

    public function handle(string $request): void {
        if ($this->process($request)) {
            return;
        }
        if ($this->next) {
            $this->next->handle($request);
        }
    }

    abstract protected function process(string $request): bool;
}

// 具体的な処理役
class AuthHandler extends Handler {
    protected function process(string $request): bool {
        if ($request === "auth") {
            echo "AuthHandler: 認証を処理しました\n";
            return true;
        }
        return false;
    }
}

class LogHandler extends Handler {
    protected function process(string $request): bool {
        if ($request === "log") {
            echo "LogHandler: ログを記録しました\n";
            return true;
        }
        return false;
    }
}

class ErrorHandler extends Handler {
    protected function process(string $request): bool {
        echo "ErrorHandler: 処理できないリクエスト '{$request}' を捕捉しました\n";
        return true;
    }
}

// --- 実行例 ---
$auth = new AuthHandler();
$log  = new LogHandler();
$error = new ErrorHandler();

// チェーンを構築
$auth->setNext($log)->setNext($error);

// リクエストを順に処理
$auth->handle("auth"); // → AuthHandlerが処理
$auth->handle("log");  // → LogHandlerが処理
$auth->handle("other"); // → 最後にErrorHandlerが処理

4. メリット・デメリット

メリット

  • 処理の分岐を「if-elseの塊」にせず、責任を分離できる
  • 新しい処理担当を追加しやすい(チェーンに追加するだけ)
  • 呼び出し側は「最初のハンドラに投げるだけ」でシンプルになる

デメリット

  • 処理の流れが分かりにくくなる(どこで処理されるのか呼び出し側から見えない)
  • チェーンが長いとパフォーマンスに影響する

5. 使いどころ

  • イベント処理(ボタンイベントを順に伝えるなど)
  • ログや権限チェック(複数のレイヤーで処理)
  • リクエストのバリデーション処理

処理を直列につないで、どこかで担当する」という設計にしたいとき、Chain of Responsibilityパターンが有効です。

Discussion