0
1

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が必要か?

❌ 全ての処理を一箇所にまとめると、責務が集中してしまう

def handle_request(request):
    if is_valid(request):
        if is_authenticated(request):
            if is_authorized(request):
                ...

処理フローがネストし、責務が密結合になる


✅ 責任を分割し、必要に応じて次のハンドラに委譲する

handler = AuthHandler(ValidationHandler(LoggingHandler()))
handler.handle(request)

処理の連鎖が明示化され、柔軟なフロー制御が可能に


2. 基本構造

✅ Handler 抽象クラス

class Handler:
    def __init__(self, next_handler=None):
        self._next = next_handler

    def handle(self, request):
        raise NotImplementedError

    def next(self, request):
        if self._next:
            self._next.handle(request)

✅ 具体的なハンドラ

class LoggingHandler(Handler):
    def handle(self, request):
        print(f"[LOG] リクエスト受信: {request}")
        self.next(request)

class ValidationHandler(Handler):
    def handle(self, request):
        if not request.get("data"):
            print("バリデーションエラー: data がありません")
            return
        self.next(request)

class AuthHandler(Handler):
    def handle(self, request):
        if request.get("auth") != "secret":
            print("認証エラー: 認証トークンが無効です")
            return
        print("認証成功")
        self.next(request)

✅ 使用例

chain = AuthHandler(ValidationHandler(LoggingHandler()))

req = {"auth": "secret", "data": "payload"}
chain.handle(req)

出力:

認証成功  
[LOG] リクエスト受信: {'auth': 'secret', 'data': 'payload'}

3. Python的応用:関数型での実装も可能

def chain(*handlers):
    def wrapped(request):
        for handler in handlers:
            if not handler(request):
                break
    return wrapped

def log_handler(request):
    print(f"[LOG] {request}")
    return True

def auth_handler(request):
    if request.get("auth") == "ok":
        return True
    print("Auth failed")
    return False

request_chain = chain(auth_handler, log_handler)
request_chain({"auth": "ok"})

軽量なデコレーションベースで処理連鎖を構成可能


4. 実務ユースケース

✅ Webリクエストの中間処理(ミドルウェア)

→ 認証・ログ・バリデーションなどを処理チェーンとして分離


✅ イベントディスパッチャ(キーボード、UI入力)

→ 入力を優先順位付きに順次ハンドリング


✅ ログ処理(複数ハンドラで出力形式を切り替え)

→ コンソール → ファイル → リモート送信などの多段構成


✅ AIパイプラインやETLの処理段階制御

→ 入力 → 正規化 → 検証 → 推論 → 書き出しなどの連鎖的処理


5. よくある誤用と対策

❌ ハンドラが次の処理を呼び忘れて処理が止まる

→ ✅ next()の呼び出しルールを明確に設計し、ベースクラスで統一


❌ 状態の共有が難しい(各ハンドラが独立しすぎる)

→ ✅ 共通の contextrequest オブジェクトを共有する設計に


❌ 例外処理やフロー制御が入り乱れやすい

→ ✅ エラー時の中断やログ出力の責任を分離設計する


結語

Chain of Responsibility パターンとは、“責任の順序を構造で定義し、流れるように処理を受け渡す設計”である。

  • 処理を段階的に分離し、動的な連鎖を可能にする
  • 単一責任原則に従い、ハンドラの再利用・差し替えが容易
  • Pythonではクラスでも関数でも、簡潔かつ拡張性のある実装が可能

Pythonicとは、“処理を柔らかく分けて、流れでつなげること”。
Chain of Responsibility パターンは、その柔軟性と秩序を、処理の連なりに刻む技法である。

0
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?