このページでは、GoF(Gang of Four)によって提唱されたデザインパターンの一つである「Chain of Responsibilityパターン」について解説します。
特にJavaを用いた実装例を中心に、C++やC#などでも応用可能な設計手法を紹介します。
Chain of Responsibilityパターンは、複数のオブジェクトが連携して処理を行う場面で役立つパターンです。
このパターンを使うことで、オブジェクト同士の結びつきを緩く保ち、柔軟性を向上させることができます。
Chain of Responsibilityとは
Chain of Responsibilityパターンとは、複数の処理オブジェクトが順次連携し、ある条件に応じて処理を引き継ぐ仕組みを提供するデザインパターンです。
このパターンは、リクエストを受けた最初のオブジェクトがそのリクエストを処理できるかどうかを判断し、処理できない場合には次のオブジェクトにリクエストを渡します。
これを「チェーン」として繋いでいくことが特徴です。
目的
Chain of Responsibilityパターンの目的は、オブジェクト同士の結合度を下げ、柔軟で拡張可能なシステムを構築することです。
具体的には、処理の流れを変更したり、新しい処理を追加する際に既存コードを修正することなく、容易に拡張できる仕組みを提供します。
メリットとデメリット
メリットとしては、処理の流れを簡単に変更できる点や、新しい処理の追加が容易である点が挙げられます。
一方で、デメリットとしては、処理の流れが複雑になる場合があり、どのオブジェクトが最終的にリクエストを処理するのかを追跡するのが難しくなる可能性があることです。
Chain of Responsibilityの使い方
Chain of Responsibilityパターンの主な使い方は、イベント処理やログ出力、バリデーションなどの処理が複数段階に分かれている場合です。
例えば、システムにおけるエラーハンドリングや、ユーザーリクエストの処理が複数の層にわたって行われる場合に適しています。
実際の使用例
例えば、GUIアプリケーションでのイベント処理や、サーバーサイドのミドルウェアでのリクエスト処理フローにChain of Responsibilityパターンが活用されます。
エラーハンドリングや、データ検証の段階的な処理などもこのパターンの典型的な使用例です。
他のデザインパターンとの比較
Chain of Responsibilityパターンは、CommandパターンやObserverパターンと組み合わせることが多いです。
特に、処理を委譲する部分がある場合はCommandパターンと相性が良く、通知機能が必要な場合にはObserverパターンとの併用が効果的です。
Chain of Responsibility実装サンプル
ここでは、Javaを使用したChain of Responsibilityパターンの実装サンプルを紹介します。
サンプルコードの説明
このサンプルでは、複数のエラーハンドラーがリクエストを順次処理していく様子を再現しています。
// 抽象ハンドラークラス
abstract class Handler {
protected Handler next;
public void setNext(Handler next) {
this.next = next;
}
public abstract void handleRequest(String request);
}
// 具体的なハンドラークラスA
class ConcreteHandlerA extends Handler {
public void handleRequest(String request) {
if (request.equals("A")) {
System.out.println("ConcreteHandlerAがリクエストを処理しました。");
} else if (next != null) {
next.handleRequest(request);
}
}
}
// 具体的なハンドラークラスB
class ConcreteHandlerB extends Handler {
public void handleRequest(String request) {
if (request.equals("B")) {
System.out.println("ConcreteHandlerBがリクエストを処理しました。");
} else if (next != null) {
next.handleRequest(request);
}
}
}
// メインクラス
public class ChainOfResponsibilityExample {
public static void main(String[] args) {
// ハンドラーのチェーンを作成
Handler handlerA = new ConcreteHandlerA();
Handler handlerB = new ConcreteHandlerB();
handlerA.setNext(handlerB);
// リクエストを処理
handlerA.handleRequest("B");
}
}
サンプルコードの解説
上記のコードでは、Handlerクラスがリクエストを処理する抽象クラスとして定義されています。
ConcreteHandlerAとConcreteHandlerBがその具体的な実装であり、それぞれ特定のリクエストを処理する役割を持っています。
mainメソッドでは、ハンドラー同士をチェーン状に連結し、リクエストに応じて適切なハンドラーが処理を行います。
この例では、リクエスト「B」がConcreteHandlerBによって処理されます。
まとめ
Chain of Responsibilityパターンは、複数のオブジェクトが順に連携してリクエストを処理する柔軟な設計を提供します。
このパターンを利用することで、処理フローを柔軟に変更したり、拡張することが可能になります。
特にエラーハンドリングやバリデーション、イベント処理など、段階的な処理が必要なシステムで有用です。
Javaだけでなく、C++やC#などのオブジェクト指向言語でも同様の設計が可能ですので、ぜひ応用してみてください。