[Design Pattern]


[Design Pattern] 1
책임의 사슬

책임 사슬 패턴이란 무엇입니까?

책임 사슬 패턴은 객체의 처리를 순차적으로 연결된 핸들러 객체에 위임하고 이를 통해 요청을 처리하는 패턴입니다. 즉, 개체가 무언가를 처리해야 할 때 해당 프로세스를 담당하는 개체를 직접 호출하지 않고 요청을 받은 개체가 요청을 체인의 다음 개체로 전달합니다. 또한 핸들러 객체를 동적으로 추가하거나 삭제할 수 있으므로 핸들러 객체를 추가하거나 삭제하는 것만으로 프로그램 동작을 변경할 수 있습니다.

책임 사슬 패턴의 구성 요소

이 패턴은 일반적으로 다음 구성 요소로 구성됩니다.

  1. 처리기 인터페이스 또는 추상 클래스: 처리기 개체가 구현해야 하는 메서드를 정의합니다. 이 인터페이스 또는 추상 클래스에는 다음 핸들러 개체를 설정하기 위한 메서드와 요청을 처리하기 위한 메서드가 포함되어 있습니다.
  2. Class ConcreteHandler: 실제 처리를 담당하는 개체입니다. 이 클래스는 핸들러 인터페이스 또는 추상 클래스를 구현합니다.
  3. 클라이언트: 핸들러 개체를 연결하여 요청을 처리하는 개체입니다. 이 개체는 핸들러 개체 체인을 설정하고 요청을 보내는 일을 담당합니다.

클래스 다이어그램

다음 책임의 사슬 패턴의 클래스 다이어그램.



[Design Pattern] 2
책임 사슬 패턴 클래스 다이어그램


위의 다이어그램에서 Handler는 Handler 개체가 구현해야 하는 메서드를 정의하는 추상 클래스 또는 인터페이스입니다. 실제 처리를 담당하는 객체인 ConcreteHandler1, ConcreteHandler2, ConcreteHandler3 클래스는 Handler 클래스를 상속받아 handleRequest 메소드를 구현한다.

C++ 책임 사슬 패턴 예제

다음 책임의 사슬 패턴의 C++ 예제.


class Handler {
protected:
    Handler* successor; // NEXT 처리기 객체
public:
    virtual ~Handler() {}
    void setSuccessor(Handler* next) { successor = next; }
    virtual void handleRequest(int request) {
        if (successor != nullptr) {
            successor->handleRequest(request);
        }
    }
};

class ConcreteHandler1 : public Handler {
public:
    void handleRequest(int request) override {
        if (request >= 0 && request < 10) {
            std::cout << "ConcreteHandler1 handles request " << request << std::endl;
        }
        else if (successor != nullptr) {
            successor->handleRequest(request);
        }
    }
};

class ConcreteHandler2 : public Handler {
public:
    void handleRequest(int request) override {
        if (request >= 10 && request < 20) {
            std::cout << "ConcreteHandler2 handles request " << request << std::endl;
        }
        else if (successor != nullptr) {
            successor->handleRequest(request);
        }
    }
};

class ConcreteHandler3 : public Handler {
public:
    void handleRequest(int request) override {
        if (request >= 20 && request < 30) {
            std::cout << "ConcreteHandler3 handles request " << request << std::endl;
        }
        else if (successor != nullptr) {
            successor->handleRequest(request);
        }
    }
};

int main() {
    ConcreteHandler1 h1;
    ConcreteHandler2 h2;
    ConcreteHandler3 h3;

    h1.setSuccessor(&h2);
    h2.setSuccessor(&h3);

    h1.handleRequest(5);
    h1.handleRequest(15);
    h1.handleRequest(25);

    return 0;
}

위의 예에서 핸들러에는 setSuccessor 메소드와 handleRequest 메소드가 있습니다. setSuccessor 메소드는 다음 핸들러 객체를 설정하고 handleRequest 메소드는 요청을 처리합니다. ConcreteHandler1, ConcreteHandler2 및 ConcreteHandler3 클래스는 각각 handleRequest 메서드를 구현합니다. 따라서 요청이 들어오면 요청을 처리할 수 있는지 확인하고, 있으면 처리하고, 그렇지 않으면 요청을 다음 처리기 개체로 전달합니다.

기본 기능은 “ConcreteHandler1”, “ConcreteHandler2” 및 “ConcreteHandler3” 개체를 생성합니다. setSuccessor 핸들러 개체를 연결하는 메서드를 호출합니다. 마지막으로 handleRequest 메서드를 호출하여 요청을 처리합니다.

C# 샘플 책임 사슬 패턴

다음은 책임 사슬 패턴의 C# 예제입니다.


using System;

abstract class Handler
{
    protected Handler successor; // NEXT 처리기 객체
    public void SetSuccessor(Handler next) { successor = next; }
    public abstract void HandleRequest(int request);
}

class ConcreteHandler1 : Handler
{
    public override void HandleRequest(int request)
    {
        if (request >= 0 && request < 10)
        {
            Console.WriteLine("ConcreteHandler1 handles request " + request);
        }
        else if (successor != null)
        {
            successor.HandleRequest(request);
        }
    }
}

class ConcreteHandler2 : Handler
{
    public override void HandleRequest(int request)
    {
        if (request >= 10 && request < 20)
        {
            Console.WriteLine("ConcreteHandler2 handles request " + request);
        }
        else if (successor != null)
        {
            successor.HandleRequest(request);
        }
    }
}

class ConcreteHandler3 : Handler
{
    public override void HandleRequest(int request)
    {
        if (request >= 20 && request < 30)
        {
            Console.WriteLine("ConcreteHandler3 handles request " + request);
        }
        else if (successor != null)
        {
            successor.HandleRequest(request);
        }
    }
}

class Program
{
    static void Main(string() args)
    {
        ConcreteHandler1 h1 = new ConcreteHandler1();
        ConcreteHandler2 h2 = new ConcreteHandler2();
        ConcreteHandler3 h3 = new ConcreteHandler3();

        h1.SetSuccessor(h2);
        h2.SetSuccessor(h3);

        h1.HandleRequest(5);
        h1.HandleRequest(15);
        h1.HandleRequest(25);

        Console.ReadKey();
    }
}

구조는 C++ 예제와 거의 동일합니다. 추상 클래스 대신 추상 키워드를 사용했습니다.