Chain of Responsibility(責任の連鎖)パターンは、GoFデザインパターンの一つで、処理のリクエストを複数のオブジェクトで分担して処理する際に有用なパターンです。
このパターンを使用することで、オブジェクトが処理を持つかどうかを知らずにリクエストを渡し、適切なオブジェクトが処理する仕組みを実現できます。
本記事では、Chain of Responsibilityパターンの概要、使い方、そしてJava、C++、C#、VB.NETでの実装サンプルを紹介します。
Chain of Responsibilityパターンとは
Chain of Responsibilityパターンは、リクエストを送信者が受信者に直接送るのではなく、処理できるオブジェクトを見つけるまで一連のオブジェクトを通過させる設計パターンです。
複数の処理者(ハンドラー)が連鎖し、それぞれがリクエストを処理するか、次のハンドラーに渡すかを判断します。このパターンは、分散処理や条件に応じた処理の振り分けを容易にします。
Chain of Responsibilityパターンの使い方
Chain of Responsibilityパターンは、以下のような状況で役立ちます。
- 処理を複数のオブジェクトに委ねる必要がある場合
- 処理を行うオブジェクトが事前に決まっていない場合
- 処理の順番や条件が動的に変わる可能性がある場合
たとえば、エラー処理やユーザーリクエストの処理など、複数の処理ステップが順番に行われるシナリオで利用されます。
各ステップで処理できない場合、次のオブジェクトにリクエストが渡されます。
Chain of Responsibilityパターン実装サンプル
次に、Java、C++、C#、VB.NETの4つの言語での実装サンプルを示します。
それぞれの言語でのChain of Responsibilityパターンの実装方法を確認しましょう。
JavaでのChain of Responsibilityパターン実装
public abstract class Handler {
protected Handler next;
public void setNext(Handler next) {
this.next = next;
}
public abstract void handleRequest(int request);
}
public class ConcreteHandler1 extends Handler {
public void handleRequest(int request) {
if (request < 10) {
System.out.println("ConcreteHandler1が処理: " + request);
} else if (next != null) {
next.handleRequest(request);
}
}
}
public class ConcreteHandler2 extends Handler {
public void handleRequest(int request) {
if (request >= 10 && request < 20) {
System.out.println("ConcreteHandler2が処理: " + request);
} else if (next != null) {
next.handleRequest(request);
}
}
}
public class Client {
public static void main(String[] args) {
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
handler1.setNext(handler2);
handler1.handleRequest(5);
handler1.handleRequest(15);
}
}
C++でのChain of Responsibilityパターン実装
#include
using namespace std;
class Handler {
protected:
Handler* next;
public:
Handler() : next(nullptr) {}
void setNext(Handler* nextHandler) {
next = nextHandler;
}
virtual void handleRequest(int request) = 0;
};
class ConcreteHandler1 : public Handler {
public:
void handleRequest(int request) override {
if (request < 10) {
cout << "ConcreteHandler1が処理: " << request << endl;
} else if (next != nullptr) {
next->handleRequest(request);
}
}
};
class ConcreteHandler2 : public Handler {
public:
void handleRequest(int request) override {
if (request >= 10 && request < 20) {
cout << "ConcreteHandler2が処理: " << request << endl;
} else if (next != nullptr) {
next->handleRequest(request);
}
}
};
int main() {
Handler* handler1 = new ConcreteHandler1();
Handler* handler2 = new ConcreteHandler2();
handler1->setNext(handler2);
handler1->handleRequest(5);
handler1->handleRequest(15);
delete handler1;
delete handler2;
return 0;
}
C#でのChain of Responsibilityパターン実装
using System;
abstract class Handler {
protected Handler next;
public void SetNext(Handler nextHandler) {
next = nextHandler;
}
public abstract void HandleRequest(int request);
}
class ConcreteHandler1 : Handler {
public override void HandleRequest(int request) {
if (request < 10) {
Console.WriteLine("ConcreteHandler1が処理: " + request);
} else if (next != null) {
next.HandleRequest(request);
}
}
}
class ConcreteHandler2 : Handler {
public override void HandleRequest(int request) {
if (request >= 10 && request < 20) {
Console.WriteLine("ConcreteHandler2が処理: " + request);
} else if (next != null) {
next.HandleRequest(request);
}
}
}
class Client {
static void Main(string[] args) {
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
handler1.SetNext(handler2);
handler1.HandleRequest(5);
handler1.HandleRequest(15);
}
}
VB.NETでのChain of Responsibilityパターン実装
Public MustInherit Class Handler
Protected nextHandler As Handler
Public Sub SetNext(next As Handler)
Me.nextHandler = next
End Sub
Public MustOverride Sub HandleRequest(request As Integer)
End Class
Public Class ConcreteHandler1
Inherits Handler
Public Overrides Sub HandleRequest(request As Integer)
If request < 10 Then
Console.WriteLine("ConcreteHandler1が処理: " & request)
ElseIf nextHandler IsNot Nothing Then
nextHandler.HandleRequest(request)
End If
End Sub
End Class
Public Class ConcreteHandler2
Inherits Handler
Public Overrides Sub HandleRequest(request As Integer)
If request >= 10 And request < 20 Then
Console.WriteLine("ConcreteHandler2が処理: " & request)
ElseIf nextHandler IsNot Nothing Then
nextHandler.HandleRequest(request)
End If
End Sub
End Class
Module Client
Sub Main()
Dim handler1 As Handler = New ConcreteHandler1()
Dim handler2 As Handler = New ConcreteHandler2()
handler1.SetNext(handler2)
handler1.HandleRequest(5)
handler1.HandleRequest(15)
End Sub
End Module
まとめ
Chain of Responsibilityパターンは、複数のハンドラーに対して処理を分担させることができ、処理の柔軟性や拡張性を高めるのに役立ちます。
今回紹介したJava、C++、C#、VB.NETの実装例を参考に、自身のプロジェクトに応じた実装を検討してください。
このパターンを使うことで、処理の分散や責任の明確化が図れ、よりモジュール化されたコードを書くことが可能です。
