1. パターンの意図
責任の連鎖(Chain of Responsibility, CoR)パターン は、
複数の処理者(Handler)を連鎖させ、リクエストを順番に渡していく デザインパターンです。
解決する問題
- 処理の担当者を呼び出し側が決め打ちしたくない
- どのハンドラが処理するか実行時に決めたい
- if/else のネストが増えすぎるのを避けたい
ポイント
- Handler:共通インターフェース、次のハンドラを保持
- ConcreteHandler:リクエストを処理するか、次へ渡す
- Client:最初のハンドラにリクエストを渡すだけ
2. UML 図
3. Flutter / Dart 実装例
Handler 抽象
abstract class Handler {
Handler? _next;
Handler setNext(Handler next) {
_next = next;
return next;
}
void handle(String request) {
if (_next != null) {
_next!.handle(request);
}
}
}
ConcreteHandler
class AuthHandler extends Handler {
@override
void handle(String request) {
if (request == "auth") {
print("AuthHandler: handled auth request");
} else {
super.handle(request);
}
}
}
class PaymentHandler extends Handler {
@override
void handle(String request) {
if (request == "pay") {
print("PaymentHandler: handled payment request");
} else {
super.handle(request);
}
}
}
利用例
void main() {
var auth = AuthHandler();
var pay = PaymentHandler();
auth.setNext(pay);
auth.handle("auth"); // AuthHandler: handled auth request
auth.handle("pay"); // PaymentHandler: handled payment request
}
4. Android / Kotlin 実装例
Handler
abstract class Handler {
private var next: Handler? = null
fun setNext(next: Handler): Handler {
this.next = next
return next
}
open fun handle(request: String) {
next?.handle(request)
}
}
ConcreteHandler
class AuthHandler : Handler() {
override fun handle(request: String) {
if (request == "auth") {
println("AuthHandler: handled auth request")
} else {
super.handle(request)
}
}
}
class PaymentHandler : Handler() {
override fun handle(request: String) {
if (request == "pay") {
println("PaymentHandler: handled payment request")
} else {
super.handle(request)
}
}
}
利用例
fun main() {
val auth = AuthHandler()
val pay = PaymentHandler()
auth.setNext(pay)
auth.handle("auth") // AuthHandler: handled auth request
auth.handle("pay") // PaymentHandler: handled payment request
}
5. 実務ユースケース
Flutter
- 複数のバリデーションルールを順に適用
- Middleware のようにリクエスト処理をチェーンする
- Flutter Bloc / Redux の Middleware 構造に近い
Android / Kotlin
- OkHttp の Interceptor チェーン
- 入力検証処理(必須チェック → 形式チェック → ビジネスルールチェック)
- 認証フロー(API Key → JWT → Refresh Token)
6. メリット / デメリット
メリット
- 呼び出し側が「誰が処理するか」を意識しなくてよい
- 責任を動的に差し替え可能
- if/else の分岐地獄を避けられる
デメリット
- 責任がどこで処理されるか追跡が難しくなる
- チェーンが長くなるとパフォーマンス低下
まとめ
- 責任の連鎖パターンは「処理を複数ハンドラに順番に渡す仕組み」
- Flutter ではバリデーション/Middleware、Android では OkHttp Interceptor が代表例
- Decorator が“追加”、Proxy が“制御”、Chain は“順送り” という違いを押さえると理解しやすい