1. Chain of Responsibility Patternとは

Chain of Responsibility Patternは、リクエストの送信者と受信者を切り離し、複数のオブジェクトがリクエストを処理する機会を提供する行動デザインパターンです。各受信者は他の受信者への参照を持ち、リクエストを処理できない場合は次の受信者にリクエストを転送し、リクエストが処理されるかチェーンの末尾に達するまで続けます。

2. Chain of Responsibility Patternの特性と利点

Chain of Responsibility Patternの特性と利点は次のとおりです:

  • 送信者と受信者の切り離し: 送信者はリクエストをどの受信者が処理するかを気にする必要がなく、またチェーン内の特定のハンドラーを知る必要もありません。
  • 柔軟性: 送信者と受信者のコードを変更せずに、ハンドラーの動的な追加、削除、または順序変更が可能です。
  • 拡張性: 新しい特定のハンドラーを追加することで、責任のチェーンを簡単に拡張できます。
  • 単一責任の原則: 各特定のハンドラーは自分自身の処理ロジックについてのみ気にする必要があります。
  • 設定可能: リクエストに応じて、異なるハンドラーチェーンを設定することができ、異なるリクエストに対して異なるハンドラーチェーンを持たせることができます。

3. Chain of Responsibility Patternの実践的な応用例

Chain of Responsibility Patternには、Webアプリケーションにおけるリクエスト処理、エラー処理、イベント処理など、さまざまな実践的な応用例があります。

  • Webアプリケーションにおけるリクエスト処理:アイデンティティ認証、ロギング、権限確認など、さまざまなタイプのリクエストの処理に使用できます。
  • エラー処理:各ハンドラーが特定のタイプのエラーを処理し、必要に応じてエラーを次のハンドラーに転送するために使用できます。
  • イベント処理:ユーザークリックイベント、ネットワークリクエストイベントなど、さまざまなタイプのイベントを処理するために使用できます。

4. GolangにおけるChain of Responsibility Patternの実装

4.1 UMLクラス図

Golang Chain of Responsibility Pattern

4.2 例の紹介

上記のUMLクラス図では、抽象ハンドラー(Handler)と2つの具象ハンドラー(ConcreteHandler1およびConcreteHandler2)が定義されています。クライアント(Client)は、ハンドラーのhandleRequestメソッドを呼び出すことでリクエストを開始します。

4.3 実装ステップ1: 抽象ハンドラーインターフェースの定義

type Handler interface {
    HandleRequest(request Request) error
    SetNext(handler Handler)
}

type Request interface {
    Condition bool
}

抽象ハンドラーインターフェースでは、リクエストを処理するためのHandleRequestメソッドと、次のハンドラーを設定するためのSetNextメソッドが定義されています。

4.4 実装ステップ2: 具象ハンドラークラスの実装

type ConcreteHandler1 struct {
    next Handler
}

func (h *ConcreteHandler1) HandleRequest(request Request) error {
    // リクエストの処理ロジック
    if request.Condition {
        // リクエストの処理コード
        return nil
    } else {
        if h.next != nil {
            return h.next.HandleRequest(request)
        }
        return errors.New("ハンドラーが見つかりません")
    }
}

func (h *ConcreteHandler1) SetNext(handler Handler) {
    h.next = handler
}

type ConcreteHandler2 struct {
    next Handler
}

func (h *ConcreteHandler2) HandleRequest(request Request) error {
    // リクエストの処理ロジック
    if request.Condition {
        // リクエストの処理コード
        return nil
    } else {
        if h.next != nil {
            return h.next.HandleRequest(request)
        }
        return errors.New("ハンドラーが見つかりません")
    }
}

func (h *ConcreteHandler2) SetNext(handler Handler) {
    h.next = handler
}

具象ハンドラークラスは、抽象ハンドラーインターフェースを実装し、HandleRequestおよびSetNextメソッドをオーバーライドします。

4.5 実装ステップ3: Chain of Responsibilityの構築

handler1 := &ConcreteHandler1{}
handler2 := &ConcreteHandler2{}

handler1.SetNext(handler2)

具象ハンドラーをインスタンス化し、次のハンドラーを設定することで、Chain of Responsibilityを構築します。

4.6 実装ステップ4: クライアントコード

func main() {
    handler := &ConcreteHandler1{}

    // Chain of Responsibilityの構築
    handler.SetNext(&ConcreteHandler2{})

    // リクエストの送信
    handler.HandleRequest(Request{Condition: true})
}

クライアントコードでは、具象ハンドラーがインスタンス化され、次のハンドラーが設定され、その後HandleRequestメソッドが呼び出されてリクエストが送信されます。