How to Create Chain in Chain of Responsibility Design Pattern?

In modern software development, design patterns are important in structuring code and making it easy to maintain. One such design pattern is the Chain of Responsibility Design Pattern. Whether you're working with C++ or any other object-oriented language, the Chain of Responsibility (CoR) pattern offers a way to handle requests through a series of handlers, each capable of processing or passing the request along.

In this article, we'll explore how to create a chain in the Chain of Responsibility Design Pattern, particularly focusing on C++ programming. We'll walk through an implementation, discuss how it works, and explain why it’s useful when flexible request-handling logic is needed.

You might also want to read about Decorator Design Pattern. Designing Design Patterns with C#

 What is the Chain of Responsibility Design Pattern?

The Chain of Responsibility Design Pattern is a behavioral design pattern that allows an object to pass a request through a chain of potential handlers. Once the chain is established each handler processes the request or passes it to the next handler in the chain. This pattern promotes loose coupling between the sender and the receiver of a request, allowing modification to the chain's structure without impacting the client code.

In a typical C++ coding scenario, the Chain of Responsibility can be visualized as a linked list where each node (or handler) decides whether it can process the request. If it can process, it goes on to process the request. If not, it passes the request to the next node in the chain.

 When to Use the Chain of Responsibility Pattern

The Chain of Responsibility pattern is useful when:

- You want to decouple request senders from receivers.

- Multiple objects can handle a request, but you don’t know which one will handle it in advance.

- You need to add flexibility to the request-handling structure without changing the client's code.

For example, in a C++ software application where multiple services can process a user action—such as logging in or performing validation—this pattern can simplify your architecture(like we are doing as part of simplifyyourday 😊) and reduce tight coupling.

 Step-by-Step: Creating the Chain in C++

Let’s take a look at how to implement the Chain of Responsibility in C++. Imagine we are building a logging system where different log levels (Info, Warning, Error) must be processed by different handlers.

#include <iostream>

#include <vector>

#include <ctime>

using namespace std;

 

class Base

{

               Base *next; // 1. "next" pointer in the base class

public:

               Base()

               {

                              next = 0;

               }

               void setNext(Base *n)

               {

                              next = n;

               }

               void add(Base *n)

               {

                              if (next)

                                             next->add(n);

                              else

                                             next = n;

               }

               // 2. The "chain" method in the base class always delegates to the next obj

               virtual void handle(int i)

               {

                              next->handle(i);

               }

};


 Concrete Handlers

 

Now we create the specific handlers that will process various log levels:

 

class Handler1 : public Base

{

public:

               /*virtual*/void handle(int i)

               {

                              if (rand() % 3)

                              {

                                             // 3. Don't handle requests 3 times out of 4

                                             cout << "H1 passed " << i << "  ";

                                             Base::handle(i); // 3. Delegate to the base class

                              }

                              else

                                             cout << "H1 handled " << i << "  ";

               }

};

 

class Handler2 : public Base

{

public:

               /*virtual*/void handle(int i)

               {

                              if (rand() % 3)

                              {

                                             cout << "H2 passed " << i << "  ";

                                             Base::handle(i);

                              }

                              else

                                             cout << "H2 handled " << i << "  ";

               }

};

 

class Handler3 : public Base

{

public:

               /*virtual*/void handle(int i)

               {

                              if (rand() % 3)

                              {

                                             cout << "H3 passed " << i << "  ";

                                             Base::handle(i);

                              }

                              else

                                             cout << "H3 handled " << i << "  ";

               }

};

 

Each handler specializes in processing a specific request. If it can't handle the request, it forwards it to the next handler in the chain.

 

Building the Chain

 

int main()

{

               srand(time(0));

               Handler1 root;

               Handler2 two;

               Handler3 thr;

               root.add(&two);

               root.add(&thr);

               thr.setNext(&root);

               for (int i = 1; i < 10; i++)

               {

                              root.handle(i);

                              cout << '\n';

               }

}

In this setup, we link the handlers into a chain. The first handler processes INFO-level logs, followed by WARNING and ERROR handlers. When a request is passed to the chain, each handler evaluates whether it can handle the request or pass it to the next one.

 Benefits of Chain of Responsibility in C++

- Flexibility: You can modify the sequence of handlers easily by changing their order.

- Loose Coupling: The sender of the request doesn’t need to know which handler will process it, making your code more maintainable.

- Open/Closed Principle: You can extend the chain by adding new handlers without modifying existing ones.

 Enhancing Flexibility

The Chain of Responsibility pattern allows you to add more handlers over time without modifying existing code, following SOLID principles.

This pattern is also widely used in scenarios such as:

- Event handling systems: Where multiple listeners may need to handle an event.

- Middleware in web development: Processing requests in stages.

- Command processing: Where multiple commands can be issued and handled by different receivers.

For more in-depth information about design patterns, you can visit this Gang of Four DesignPatterns.

 Conclusion 

The Chain of Responsibility Design Pattern provides a flexible and decoupled way to handle requests in your applications. By allowing requests to pass through a chain of handlers, this pattern makes your code cleaner, more flexible, and easier to maintain. In C++ programming, it's a highly effective pattern when you need to delegate responsibilities across various objects, especially in complex systems.

If you're interested in exploring more about C++ design patterns, be sure to check out other patterns like the Strategy Pattern or the Decorator Pattern, as they also complement this architecture.

Comments

Popular posts from this blog

Creating RESTful Minimal WebAPI in .Net 6 in an Easy Manner! | FastEndpoints

Mastering Concurrency with Latches and Barriers in C++20: A Practical Guide for Students

Graph Visualization using MSAGL with Examples