본문 바로가기
CS(Computer Science)지식/[C++] 디자인 패턴

책임 연쇄 패턴(Chain of Reponsibility Design Pattern) 이해하기 : 쉽게 설명한 디자인 패턴(C++)

by 엔지니어 청년 2024. 1. 29.

책임 연쇄 패턴은 행동 디자인 패턴 중 하나로, 요청을 처리할 수 있는 객체의 체인을 만드는 패턴입니다. 이 패턴은 요청을 보낸 객체와 요청을 받아 처리하는 객체 사이의 결합을 피하도록 돕습니다. 요청은 체인의 객체들을 통과하며, 각 객체는 요청을 처리하거나 다음 객체로 전달합니다.

1.예시 코드


다음은 C++로 작성된 책임 연쇄 패턴의 예시 코드입니다.

#include <iostream>

// Handler: Abstract base class for handlers
class Handler {
public:
    virtual Handler* setNext(Handler* handler) = 0;
    virtual std::string handle(std::string request) = 0;
};

// BaseHandler: Common chaining behavior
class BaseHandler : public Handler {
private:
    Handler* nextHandler;

public:
    BaseHandler() : nextHandler(nullptr) {}

    Handler* setNext(Handler* handler) override {
        this->nextHandler = handler;
        return handler;
    }

    std::string handle(std::string request) override {
        if (this->nextHandler) {
            return this->nextHandler->handle(request);
        }
        return {};
    }
};

// ConcreteHandler1
class ConcreteHandler1 : public BaseHandler {
public:
    std::string handle(std::string request) override {
        if (request == "Request1") {
            return "ConcreteHandler1: Handled " + request;
        } else {
            return BaseHandler::handle(request);
        }
    }
};

// ConcreteHandler2
class ConcreteHandler2 : public BaseHandler {
public:
    std::string handle(std::string request) override {
        if (request == "Request2") {
            return "ConcreteHandler2: Handled " + request;
        } else {
            return BaseHandler::handle(request);
        }
    }
};

// Client code
void clientCode(Handler* handler) {
    std::string request1 = "Request1";
    std::cout << "Client: " << request1 << std::endl;
    std::cout << "Handler: " << handler->handle(request1) << std::endl;

    std::string request2 = "Request2";
    std::cout << "Client: " << request2 << std::endl;
    std::cout << "Handler: " << handler->handle(request2) << std::endl;
}

int main() {
    ConcreteHandler1* handler1 = new ConcreteHandler1;
    ConcreteHandler2* handler2 = new ConcreteHandler2;
    handler1->setNext(handler2);

    std::cout << "Chain: ConcreteHandler1 > ConcreteHandler2" << std::endl;
    clientCode(handler1);
    std::cout << std::endl;

    delete handler1;
    delete handler2;

    return 0;
}

2.출력 결과


Chain: ConcreteHandler1 > ConcreteHandler2
Client: Request1
Handler: ConcreteHandler1: Handled Request1
Client: Request2
Handler: ConcreteHandler2: Handled Request2

3.클래스 다이어그램


+-------------------+     +-------------------+     +-------------------+
|     <<interface>> |     |                   |     |                   |
|      Handler      |<----|    BaseHandler    |<----| ConcreteHandler1  |
+-------------------+     +-------------------+     +-------------------+
| +setNext(handler: |     | -nextHandler:     |     |                   |
|   Handler*):      |     |   Handler*        |     |                   |
|   Handler* = 0    |     +-------------------+     +-------------------+
| +handle(request:  |     | +setNext(handler: |     | +handle(request:  |
|   string):        |     |   Handler*):      |     |   string):        |
|   string = 0      |     |   Handler*        |     |   string          |
+-------------------+     | +handle(request:  |     +-------------------+
                          |   string):        |
                          |   string          |
                          +-------------------+
                                    ^
                                    |
                          +-------------------+
                          |                   |
                          | ConcreteHandler2  |
                          +-------------------+
                          |                   |
                          +-------------------+
                          | +handle(request:  |
                          |   string):        |
                          |   string          |
                          +-------------------+

이 예제에서는 Handler 인터페이스가 setNexthandle 두 개의 메소드를 정의하고 있습니다. BaseHandlerHandler 인터페이스를 구현하며, setNext 메소드를 통해 다음 핸들러를 설정하고, handle 메소드를 통해 요청을 처리하거나 다음 핸들러로 전달합니다. ConcreteHandler1ConcreteHandler2BaseHandler를 상속받아 handle 메소드를 오버라이드하여 특정 요청을 처리합니다.