2
3

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-elif-else が膨張していく構造

def handle(request):
    if request.type == "A":
        return handle_a(request)
    elif request.type == "B":
        return handle_b(request)
    else:
        return default_handler(request)

条件が増えるごとにコードが冗長化し、保守性が低下


✅ チェーンに処理責任を委譲する構造へ

handler = HandlerA(HandlerB(DefaultHandler()))
response = handler.handle(request)

処理責任の分離とルーティングの柔軟化が可能に


2. 基本構造と実装

✅ 抽象ハンドラ

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

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

✅ 具体的ハンドラ

class AuthHandler(Handler):
    def handle(self, request):
        if request.get("user"):
            print("✅ Auth passed")
            return super().handle(request)
        print("❌ Auth failed")
        return "Unauthorized"

class DataValidationHandler(Handler):
    def handle(self, request):
        if "data" in request:
            print("✅ Data validated")
            return super().handle(request)
        print("❌ Invalid data")
        return "Bad Request"

class FinalHandler(Handler):
    def handle(self, request):
        print("✅ Final processing complete")
        return "Success"

✅ 実行例

pipeline = AuthHandler(DataValidationHandler(FinalHandler()))

req = {"user": "toto", "data": "payload"}
result = pipeline.handle(req)
print("Result:", result)

3. Python的に書きやすくする工夫

✅ デコレータスタイルのチェーン構築

def chain(handlers):
    for i in range(len(handlers) - 1):
        handlers[i]._next = handlers[i + 1]
    return handlers[0]
pipeline = chain([
    AuthHandler(),
    DataValidationHandler(),
    FinalHandler()
])

構造の簡素化と柔軟な再構築が容易に


4. 実務ユースケース

✅ Webリクエストの前処理パイプライン

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

✅ ログ出力:レベル別での責任転送

class InfoLogger(Handler):
    def handle(self, msg):
        if msg.level == "info":
            print("[INFO]", msg.text)
        else:
            super().handle(msg)

✅ イベント処理:フィルタ・変換・通知のチェーン構築

  • センサーデータの前処理など、動的フィルタリング構造に応用

5. よくある誤用と対策

❌ 全てのハンドラが処理してしまう

→ ✅ 一度処理されたら後続に渡さない設計(戻り値で分岐)を明確に定義する


❌ 無限ループのような循環参照を作る

→ ✅ ハンドラの終端条件を必ず設ける(デフォルトハンドラ or None)


❌ 適用範囲が広すぎてロジックが追えない

→ ✅ ハンドラごとに責務を限定し、チェーンの流れを可視化できるよう命名・構造化


結語

Chain of Responsibility パターンは、処理を段階的に分離し、
それぞれの責務を独立したハンドラとして定義することで、
動的な処理フローを構築できる構造的アプローチ
である。

  • 条件分岐からの脱却
  • 柔軟なパイプライン構築
  • 動的ルーティングやイベント処理との親和性

Pythonicとは、“流れを設計可能な構造で表現する”ことであり、
Chain of Responsibility はその思想を、可変的かつ拡張可能な形で実現する設計である。

2
3
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
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?