【ITニュース解説】Chain Of Responsibility in Python...
2025年09月05日に「Dev.to」が公開したITニュース「Chain Of Responsibility in Python...」について初心者にもわかりやすいように丁寧に解説しています。
ITニュース概要
PythonでのChain of Responsibilityパターンは、コマンド処理を複数のオブジェクトに委譲する。各オブジェクトは処理可能か判断し、不可なら次のオブジェクトへ渡す。コマンドはチェーンの末端まで伝搬し、最終的にいずれかのオブジェクトが処理する。これにより、処理ロジックとオブジェクト間の結合度を下げ、柔軟なシステム構築を可能にする。
ITニュース解説
この記事では、デザインパターンのひとつである「Chain of Responsibility(責任連鎖)」パターンについて、Pythonでの実装例を交えて解説する。このパターンは、ある処理要求(コマンド)を複数のオブジェクトが順に処理を試みる構造を提供するものだ。各オブジェクトは、自分の担当範囲であれば処理を実行し、そうでなければ次のオブジェクトに処理を委譲する。
Chain of Responsibilityパターンは、処理要求の種類や処理を担当するオブジェクトを動的に変更したい場合に有効だ。例えば、ヘルプシステム、イベント処理、認証処理など、様々な場面で応用できる。
このパターンの主要な要素は以下のとおりだ。
-
コマンド(Command): 処理要求を表すオブジェクト。この記事の例では
ICommandクラスがこれに該当する。ICommandは抽象基底クラスであり、コマンドのレベル(優先度や種類)を保持する。 -
レシーバー(Receiver): コマンドを受け取り、処理を試みるオブジェクト。
CommandReceiverクラスがこれにあたる。CommandReceiverは抽象基底クラスであり、handleCommandImplメソッドを実装する必要がある。このメソッドが実際にコマンドを処理する部分だ。また、handleCommandメソッドは、コマンド処理の全体的な流れを制御する。 -
サクセサー(Successor): 次に処理を委譲するレシーバー。
CommandReceiverクラスは、コンストラクタでサクセサーを受け取る。
具体的なPythonコードを見てみよう。まず、ICommand クラスは、コマンドのレベルを初期化する。
1from abc import ABC, abstractmethod 2 3class ICommand(ABC): 4 def __init__(self, level): 5 self.level = level
次に、CommandReceiver クラスは、サクセサーを保持し、コマンドを受け取って処理を行う。handleCommandImpl メソッドは抽象メソッドであり、サブクラスで実装する必要がある。handleCommand メソッドは、handleCommandImpl を呼び出し、処理が成功しなかった場合はサクセサーに処理を委譲する。
1class CommandReceiver(ABC): 2 def __init__(self, successor): 3 self.successor = successor 4 5 @abstractmethod 6 def handleCommandImpl(self, command): 7 pass 8 9 def handleCommand(self, command): 10 retType = self.handleCommandImpl(command) 11 if self.successor != None and retType == False: 12 self.successor.handleCommand(command) 13 else: 14 return
ReceiverLevel1, ReceiverLevel2, ReceiverLevel3 クラスは、CommandReceiver クラスを継承し、それぞれレベル1、レベル2、レベル3のコマンドを処理する。各クラスの handleCommandImpl メソッドは、コマンドのレベルを確認し、自分の担当範囲であれば処理を実行し、そうでなければ False を返す。
1class ReceiverLevel1(CommandReceiver): 2 def __init__(self, successor): 3 self.successor = successor 4 5 def handleCommandImpl(self, command): 6 if command.level == 1: 7 print("The Command is handled at level 1") 8 return True 9 else: 10 print("Forwarding the command from level 1 to level 2") 11 return False
ReceiverLevel2 と ReceiverLevel3 も同様の構造を持つ。ReceiverLevel3 は最後のレシーバーであるため、サクセサーは None に設定される。
最後に、メインの処理では、各レベルのコマンドとレシーバーを作成し、レシーバーを連鎖させる。そして、最も低いレベルのレシーバーにコマンドを渡す。
1if __name__ == '__main__': 2 commandLevel1 = ICommand(1) 3 commandLevel2 = ICommand(2) 4 commandLevel3 = ICommand(3) 5 6 receiverLevel3 = ReceiverLevel3(None) 7 receiverLevel2 = ReceiverLevel2(receiverLevel3) 8 receiverLevel1 = ReceiverLevel1(receiverLevel2) 9 10 receiverLevel1.handleCommand(commandLevel3)
この例では、レベル3のコマンドが最初にレベル1のレシーバーに渡される。レベル1のレシーバーは、自分の担当範囲外であるため、レベル2のレシーバーに委譲する。レベル2も同様にレベル3に委譲し、最終的にレベル3のレシーバーがコマンドを処理する。
Chain of Responsibility パターンを利用することで、処理ロジックと処理を担当するオブジェクトの間の結合度を下げることができる。これにより、新しい処理要求やレシーバーの追加が容易になり、システムの柔軟性が向上する。