C++ Chain of Responsibility Pattern Example

1. Definition

The Chain of Responsibility Pattern decouples the sender of a request from its receivers by allowing multiple objects to handle the request. These objects are linked in a chain, and the request is passed along the chain until one of the objects handles it.

2. Problem Statement

Imagine a scenario where a request can be handled by several objects in a system, but only one of them should process it based on some conditions. How do you determine which object will handle the request without tightly coupling the sender to the specific handler?

3. Solution

Create a chain of potential handler objects where each handler decides either to process the request or pass it along to the next handler in the chain. This way, the system remains decoupled and scalable.

4. Real-World Use Cases

1. GUI systems where events can be handled by various widgets or passed up the hierarchy.

2. Middleware in web servers that process requests.

3. Workflow processes where a task moves through a series of stages or approvals.

5. Implementation Steps

1. Define a Handler interface that declares a method for handling requests and (optionally) a method to set the next handler.

2. Each ConcreteHandler class will implement the Handler interface and define its own criteria for handling the request or passing it.

3. The client will then create a chain of handlers and send the request.

6. Implementation in C++

// Step 1: Define the Handler interface
class Handler {
protected:
    Handler* nextHandler;
public:
    Handler() : nextHandler(nullptr) {}
    virtual ~Handler() {}
    virtual void handleRequest(int value) const = 0;
    void setNextHandler(Handler* handler) { nextHandler = handler; }
};
// Step 2: Implement ConcreteHandlers
class ConcreteHandlerA : public Handler {
public:
    void handleRequest(int value) const override {
        if (value == 1) {
            std::cout << "Handler A processed the request." << std::endl;
        } else if (nextHandler) {
            nextHandler->handleRequest(value);
        }
    }
};
class ConcreteHandlerB : public Handler {
public:
    void handleRequest(int value) const override {
        if (value == 2) {
            std::cout << "Handler B processed the request." << std::endl;
        } else if (nextHandler) {
            nextHandler->handleRequest(value);
        }
    }
};
int main() {
    Handler* handlerA = new ConcreteHandlerA();
    Handler* handlerB = new ConcreteHandlerB();
    handlerA->setNextHandler(handlerB);
    handlerA->handleRequest(1);
    handlerA->handleRequest(2);
    delete handlerA;
    delete handlerB;
    return 0;
}

Output:

Handler A processed the request.
Handler B processed the request.

Explanation:

1. The Handler interface defines the method handleRequest and a method to set the next handler in the chain.

2. Concrete implementations ConcreteHandlerA and ConcreteHandlerB decide if they can handle the request or pass it to the next handler.

3. In the main function, two handlers are chained together. Requests are sent to the first handler (handlerA). If it can't process, it delegates to the next.

7. When to use?

Use the Chain of Responsibility pattern when:

1. More than one object can handle a request, and the handler isn't predetermined. The handler should be determined automatically at runtime.

2. You want to decouple the classes that invoke operations from classes that perform the operations.

3. The set of objects that can handle a request should be specified dynamically.


Comments