The Chain of Responsibility pattern is a behavioral design pattern which allows you pass a object of a request through a chain of potential handlers until one of them handles the request. This pattern decouples the sender of a request from its receiver by giving multiple objects a chance to handle the request.
In this pattern, each handler in the chain has a reference to the next handler. When a request is received, the handler decides either to process the request or to pass it to the next handler in the chain. This continues until a handler processes the request or the end of the chain is reached.

Components of the Chain of Responsibility Pattern
There are three main components in the Chain of Responsibility pattern, we have listed them below −
- Handler − It can be an abstract class or it may be an interface which defines a method for handling requests and a method for setting the next handler in the chain.
- Concrete Handler − These are the classes that implement the handler interface and provide specific implementations for handling requests. Each concrete handler decides whether to process the request or pass it to the next handler.
- Client − The client is responsible for creating the chain of handlers and initiating the request processing by sending the request to the first handler in the chain.
Implementation of the Chain of Responsibility Pattern
Now, let’s implement the Chain of Responsibility pattern in C++.
In this example, we will take an real-world scenario where, we have a support ticket system. The tickets can be handled by different levels of support staff based on the priority and complexity of the issue.
Steps to Implement the Chain of Responsibility Pattern in C++
Following are the steps to implement the Chain of Responsibility pattern in C++:

C++ Implementation of Chain of Responsibility Pattern
Here is a simple implementation of the Chain of Responsibility pattern in C++ of the support ticket system −
#include <iostream>#include <string>usingnamespace std;// Abstract HandlerclassSupportHandler{protected:
SupportHandler* nextHandler;public:SupportHandler():nextHandler(nullptr){}voidsetNextHandler(SupportHandler* handler){
nextHandler = handler;}virtualvoidhandleRequest(const string& issue,int priority)=0;};// Concrete Handler: Level 1 SupportclassLevel1Support:public SupportHandler{public:voidhandleRequest(const string& issue,int priority)override{if(priority ==1){
cout <<"Level 1 Support handled the issue: "<< issue << endl;}elseif(nextHandler){
nextHandler->handleRequest(issue, priority);}}};// Concrete Handler: Level 2 SupportclassLevel2Support:public SupportHandler{public:voidhandleRequest(const string& issue,int priority)override{if(priority ==2){
cout <<"Level 2 Support handled the issue: "<< issue << endl;}elseif(nextHandler){
nextHandler->handleRequest(issue, priority);}}};// Concrete Handler: Level 3 SupportclassLevel3Support:public SupportHandler{public:voidhandleRequest(const string& issue,int priority)override{if(priority ==3){
cout <<"Level 3 Support handled the issue: "<< issue << endl;}elseif(nextHandler){
nextHandler->handleRequest(issue, priority);}}};intmain(){// Create handlers
Level1Support level1;
Level2Support level2;
Level3Support level3;// Set up the chain of responsibility
level1.setNextHandler(&level2);
level2.setNextHandler(&level3);// Create some support requests
level1.handleRequest("Password reset",1);
level1.handleRequest("Software installation",2);
level1.handleRequest("System crash",3);
level1.handleRequest("Unknown issue",4);// No handler for this priorityreturn0;}
In this example, we have defined an abstract handler class SupportHandler with a method to handle requests and a method to set the next handler. We then created three concrete handlers: Level1Support, Level2Support, and Level3Support, each responsible for handling requests of different priority levels.
In the main function, we created instances of each handler and set up the chain of responsibility. Finally, we created some support requests with different priority levels to demonstrate how the requests are handled by the appropriate handlers in the chain.
Pros and Cons of Chain of Responsibility Pattern
Here are some pros and cons of using the Chain of Responsibility pattern −
| Pros | Cons |
|---|---|
| Makes it easy to separate who sends a request from who handles it | Can be tricky to figure out where a request was handled |
| Lets you add or remove support levels without much hassle | If the chain gets too long, it might slow things down |
| Simple to organize and keep your code tidy | Some requests might not get handled at all |
| You can change the order of handlers whenever you need | Itâs not always obvious how the request moves through the chain |
| Each handler can focus on just one thing | You need to plan carefully how handlers work together |
| You can reuse the same handler in different chains | Having lots of handlers might use more memory |
Real-World Examples of Chain of Responsibility Pattern
Here are some real-world examples where the Chain of Responsibility pattern is commonly used −
- Event Handling in Apps − When you click a button or press a key, the event travels through a series of handlers. The first one that knows what to do with it takes care of it, just like passing a message down a line until someone responds.
- Logging − When something happens in a program, a log message might go through several loggersâone for errors, one for warnings, one for infoâuntil it finds the right place to be recorded.
- Customer Support − If youâve ever contacted customer support, you know your question might get passed from one person to another until someone can actually help you. Thatâs the chain of responsibility in action.
- Web Requests − When you visit a website, your request can go through different stepsâlike checking if youâre logged in, filtering out bad requests, or adding extra infoâbefore it gets to the part that shows you the page.
Conclusion
In this chapter, weâve seen what the Chain of Responsibility pattern is, how it works, and how to use it in C++. Itâs a handy way to keep your code flexible and easy to maintain by letting requests find the right handler without everyone needing to know about each other.
Leave a Reply