Chain of Responsibilityパターンとは | GoFデザインパターン

記事内に広告が含まれています。

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の実装例を参考に、自身のプロジェクトに応じた実装を検討してください。

このパターンを使うことで、処理の分散や責任の明確化が図れ、よりモジュール化されたコードを書くことが可能です。

オブジェクト指向プログラミングにおけるGoFの23のデザインパターン
デザインパターンは、ソフトウェア設計の問題を効果的に解決するための再利用可能な解決策です。本記事では、GoF(Gang ...
タイトルとURLをコピーしました