🎉
デザインパターンを学ぶ #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