0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pythonで実装するChain of Responsibilityパターン:責任をリレーする柔軟な処理フロー

Posted at

概要

Chain of Responsibility(責任の連鎖)パターンは、
処理の責任を複数のオブジェクト間でリレー形式に渡しながら分散させる設計パターンである。

各処理単位は自身で対応できるかを判断し、できなければ次に委譲。
この構造により、送信者は具体的な処理担当者を知ることなく処理を依頼できる


1. なぜChain of Responsibilityが必要か?

❌ 処理の分岐が呼び出し元に集中し、密結合かつ拡張性が低い

if req.type == "auth":
    handle_auth(req)
elif req.type == "log":
    handle_log(req)

条件が増えるたびにコードが膨張し、変更に弱くなる


✅ 各責任を持つハンドラに分け、処理を順番に委譲していく構造へ

handler1.set_next(handler2).set_next(handler3)
handler1.handle(req)

処理の流れを動的に構築可能かつ、責任の局所化が実現できる


2. 基本構造

✅ Handler(共通インターフェース)

class Handler:
    def set_next(self, handler):
        self._next = handler
        return handler

    def handle(self, request):
        if hasattr(self, '_next'):
            return self._next.handle(request)
        return None

✅ ConcreteHandlers(具体的な責任を持つクラス)

class AuthHandler(Handler):
    def handle(self, request):
        if request == "auth":
            print("[AuthHandler] 認証処理を実行")
            return True
        return super().handle(request)

class LogHandler(Handler):
    def handle(self, request):
        if request == "log":
            print("[LogHandler] ログ記録処理を実行")
            return True
        return super().handle(request)

class FallbackHandler(Handler):
    def handle(self, request):
        print(f"[FallbackHandler] 未対応のリクエスト: {request}")
        return False

✅ 使用例

auth = AuthHandler()
log = LogHandler()
fallback = FallbackHandler()

auth.set_next(log).set_next(fallback)

auth.handle("auth")    # [AuthHandler] 認証処理を実行
auth.handle("log")     # [LogHandler] ログ記録処理を実行
auth.handle("unknown") # [FallbackHandler] 未対応のリクエスト: unknown

3. Python的応用:関数型での簡易実装

def chain(*handlers):
    def handle(request):
        for handler in handlers:
            if handler(request):
                return True
        print("すべてのハンドラがリクエストを処理できませんでした")
        return False
    return handle

def auth_handler(req): return req == "auth" and print("auth済み")
def log_handler(req): return req == "log" and print("ログ処理")

handle = chain(auth_handler, log_handler)
handle("auth")
handle("log")
handle("other")

関数の連鎖でも同様の構造が可能。軽量な場合に有効


4. 実務ユースケース

✅ リクエスト処理パイプライン(Web/Middleware)

認証 → バリデーション → ログ → 処理


✅ 入力検証の段階処理

入力値を条件ごとに順番に検証・エラーハンドリング


✅ イベントハンドラの委譲処理

複数のレイヤーでイベント処理を試み、最終的に対応者に届く


✅ 通知やアラートの優先ルーティング

通知条件に応じたハンドラの選定・実行


5. よくある誤用と対策

❌ ハンドラ同士が互いを知りすぎている(tight coupling)

→ ✅ set_next で明示的に構築し、内部には依存させない


❌ チェーンの構築を分散して行い、追跡不可能に

→ ✅ チェーン構築は集中管理し、処理の流れが明示的に分かるようにする


❌ 各ハンドラが責任範囲を曖昧に処理し始める

→ ✅ それぞれが何を処理するのかを明確に定義する


結語

Chain of Responsibilityパターンとは、“責任を分けて、順に流しながら柔軟に処理する設計”である。

  • 各処理単位が自律し、順番に委譲される構造で柔軟な処理フローを実現
  • 新たな責任の追加や並び替えが容易で、動的な処理チェーンの構築に最適
  • Pythonではクラス・関数の両方で実装可能で、明快かつ表現力豊かな設計ができる

Pythonicとは、“誰が処理するかではなく、誰が処理できるかで構造を設計すること”。
Chain of Responsibilityパターンはその責任の知性を、処理の連続性として表現する技法である。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?