Chain of Responsibility Design Pattern in C#

Chain of Responsibility Design Pattern in C#

In this article, I will discuss the Chain of Responsibility Design Pattern in C# with Examples. Please read our previous article discussing the Observer Design Pattern in C# with one Real-Time Example. The Chain of Responsibility Design Pattern falls under the category of Behavioral Design Pattern. As part of this article, we will discuss the following pointers.

  1. What is the Chain of Responsibility Design Pattern?
  2. Understanding the Chain of Responsibility Design Pattern
  3. Real-time Example of Chain of Responsibility Design Pattern
  4. Implementation of Chain of Responsibility Design Pattern in C#
What is the Chain of Responsibility Design Pattern?

According to the Gang of Four Definitions, the Chain of Responsibility Design Pattern states that Avoid coupling the sender of a request to its receiver by giving more than one receiver object a chance to handle the request. Chain the receiving objects and pass the request along until an object handles it.

In simple words, we can say that the chain of responsibility design pattern creates a chain of receiver objects for a given request. In this design pattern, normally, each receiver contains a reference to another receiver. If one receiver cannot handle the request, it passes the same request to the next receiver, and so on. One receiver handles the request in the chain, or one or more receivers handle the request.

Understanding the Chain of Responsibility Design Pattern:

Please look at the following diagram to understand the Chain of Responsibility Design Pattern. As shown in the diagram below, on the left side, we have a client. On the right side, we have multiple receivers chained together (i.e., receiver 1 has a reference to receiver 2, receiver 2 has a reference to receiver 3, and so on).

What is the Chain of Responsibility Design Pattern?

Here, the client sends the request to the Chain of Receivers. In the chain of receivers, the first receiver is Receiver 1. So, the request will come to Receiver 1, and Receiver 1 will check whether it can handle the request. If it can handle the request, then it will handle the request and then check whether further processing is needed for the request or not. If further processing is needed, it will send the request to the next receiver (i.e., Receiver 2) in the chain of receivers. If the request does not need further processing, it will not pass it to the next receiver.

Receiver 2 will then check whether it can handle the request or not. If it can handle the request, then it will handle the request and then check whether further processing is needed or not. If further processing is needed, it will send the request to the next receiver (i.e., Receiver 3). It will not pass the request to the next receiver if it doesn’t need further processing. In this way, the chain of responsibility works.

Real-Time Example to Understand Chain of Responsibility Design Pattern:

Let us understand the Chain of Responsibility Design Pattern with one Real-Time Example. Please have a look at the following image. As shown in the image below, we have an ATM machine and four handlers. The TwoThousandhandler will give 2000 rupees. Similarly, the FiveHundredHandler will give 500 hundred rupees and the same for 200 and 100 handlers.

Real-Time Example to Understand Chain of Responsibility Design Pattern

Now, Anurag wants to withdraw 4600 rupees from the ATM machine. So, what the ATM machine will do is send the request to the first handler, i.e., the TwoThousandHandler, and the TwoThousandHandler will check the amount and give two 2000 rupees notes, and then the remaining amount is 600 rupees. So, the TwoThousandHandler will send the request to the FiveHundredHandler. Then, the FiveHundredHandler will check the remaining amount and give one 500 rupee note, and the remaining amount is 100 rupees. So, the FiveHundredHandler will forward the request to the next handler, i.e., TwoHundredHandler, and the TwoHundredHandler will check the remaining amount, which is 100. So, it can’t handle the request and simply forwards it to the next handler, HundredHandler. The HundredHandler checks the remaining amount, which is 100, and will give one 100 rupees note. This way, it will handle the request and provide Anurag with 4600 (2 * 2000, 1*500, and 1*100). This is one of the best examples of one or more receivers in the chain handling the request.

Implementation of Chain of Responsibility Design Pattern in C#:

Let us implement the above-discussed example step by step using the Chain of Responsibility Design Pattern in C#.

Step1: Creating Abstract Handler

Please create a class file named Handler.cs and copy and paste the following code. Here, you can see that we created one variable of type Handler (i.e., NextHandler), and this variable will hold the reference of the Next Handler. We have initialized this variable through the class constructor. What is the next handler? If this is not clear now, don’t worry; you will understand the need for this variable after a while. The concrete handler classes will implement this abstract DispatchNote() method. The following code is self-explained, so please go through the comment lines for a better understanding.

namespace ChainOfResponsibilityDesignPattern
{
    // Handler Abstract Class
    // The Default Chaining Behavior can be implemented inside the abstract handler class.
    public abstract class Handler
    {
        //The NextHandler will hold the reference of the next handler
        public Handler NextHandler;

        //Initializing NextHandler reference using the class constructor
        public void SetNextHandler(Handler NextHandler)
        {
            this.NextHandler = NextHandler;
        }

        //The following Method needs to be implemented by the Child handler Classes
        //The following method is going to handle a request.
        public abstract void DispatchNote(long requestedAmount);
    }
}
Step2: Creating Concrete Handlers

Here, we will create four handlers (TwoThousandHandler, FiveHundredHandler, TwoHundredHandler, and HundredHandler) to handle the respective currency. Create a class file named TwoThousandHandler.cs and copy and paste the following code. This class inherits from the Handler abstract class and implements the abstract DispatchNote method. The following code is self-explained, so please go through the comment lines for a better understanding.

using System;
namespace ChainOfResponsibilityDesignPattern
{
    //Concrete Handler 1
    //The following class implement the Handler abstract class and 
    //Provide Implementation for DispatchNote abstract method
    public class TwoThousandHandler : Handler
    {
        public override void DispatchNote(long requestedAmount)
        {
            //First Check the Number of 2000 Notes To Be Dispatched
            long numberofNotesToBeDispatched = requestedAmount / 2000;
            if (numberofNotesToBeDispatched > 0)
            {
                if (numberofNotesToBeDispatched > 1)
                {
                    Console.WriteLine(numberofNotesToBeDispatched + " Two Thousand notes are dispatched by TwoThousandHandler");
                }
                else
                {
                    Console.WriteLine(numberofNotesToBeDispatched + " Two Thousand note is dispatched by TwoThousandHandler");
                }
            }

            //Then check the Pending amount
            long pendingAmountToBeProcessed = requestedAmount % 2000;

            //If the Pending amount is greater than 0, then call the next handler to handle the request
            if (pendingAmountToBeProcessed > 0)
            {
                //For TwoThousandHandler, the next handler is FiveHundredHandler 
                NextHandler.DispatchNote(pendingAmountToBeProcessed);
            }
        }
    }
}

First, as part of the DispatchNote() method, we calculate the number of 2000 notes to be dispatched. If the amount is greater than 1, then we print how many 2000 notes are in the console window. Then we check the remaining amount, and if the remaining is greater than 0, we call the DispatchNote() method of the next handler (NextHandler), i.e., the FiveHundredHandler.

FiveHundredHandler:

Create a class file named FiveHundredHandler.cs and copy and paste the following code. The following code is self-explained, so please go through the comment lines for a better understanding.

using System;
namespace ChainOfResponsibilityDesignPattern
{
    //Concrete Handler 2
    //The following class implement the Handler abstract class and 
    //Provide Implementation for DispatchNote abstract method
    public class FiveHundredHandler : Handler
    {
        public override void DispatchNote(long requestedAmount)
        {
            //First Check the Number of 500 Notes To Be Dispatched
            long numberofNotesToBeDispatched = requestedAmount / 500;
            if (numberofNotesToBeDispatched > 0)
            {
                if (numberofNotesToBeDispatched > 1)
                {
                    Console.WriteLine(numberofNotesToBeDispatched + " Five Hundred notes are dispatched by FiveHundredHandler");
                }
                else
                {
                    Console.WriteLine(numberofNotesToBeDispatched + " Five Hundred note is dispatched by FiveHundredHandler");
                }
            }

            //Then check the Pending amount
            long pendingAmountToBeProcessed = requestedAmount % 500;

            //If Pending amount is greater than 0, then call the next handler to handle the request
            if (pendingAmountToBeProcessed > 0)
            {
                //For FiveHundredHandler, the next handler is TwoHundredHandler  
                NextHandler.DispatchNote(pendingAmountToBeProcessed);
            }
        }
    }
}

Here, we also do the same thing as in the previous handler. Similarly, we need to implement TwoHundredHandler and HundredHandler.

TwoHundredHandler:

Create a class file named TwoHundredHandler.cs and copy and paste the following code. The following code is self-explained, so please go through the comment lines for a better understanding.

using System;
namespace ChainOfResponsibilityDesignPattern
{
    //Concrete Handler 3
    //The following class implement the Handler abstract class and 
    //Provide Implementation for DispatchNote abstract method
    public class TwoHundredHandler : Handler
    {
        public override void DispatchNote(long requestedAmount)
        {
            //First Check the Number of 200 Notes To Be Dispatched
            long numberofNotesToBeDispatched = requestedAmount / 200;
            if (numberofNotesToBeDispatched > 0)
            {
                if (numberofNotesToBeDispatched > 1)
                {
                    Console.WriteLine(numberofNotesToBeDispatched + " Two Hundred notes are dispatched by TwoHundredHandler");
                }
                else
                {
                    Console.WriteLine(numberofNotesToBeDispatched + " Two Hundred note is dispatched by TwoHundredHandler");
                }
            }

            //Then check the Pending amount
            long pendingAmountToBeProcessed = requestedAmount % 200;

            //If the Pending amount is greater than 0, then call the next handler to handle the request
            if (pendingAmountToBeProcessed > 0)
            {
                //For TwoHundredHandler, the next handler is HundredHandler 
                NextHandler.DispatchNote(pendingAmountToBeProcessed);
            }
        }
    }
}
HundredHandler:

Create a class file with the name HundredHandler.cs and copy and paste the following code. The following code is self-explained, so please go through the comment lines for a better understanding.

using System;
namespace ChainOfResponsibilityDesignPattern
{
    //Concrete Handler 4
    //The following class implement the Handler abstract class and 
    //Provide Implementation for DispatchNote abstract method
    public class HundredHandler : Handler
    {
        public override void DispatchNote(long requestedAmount)
        {
            //First Check the Number of 100 Notes To Be Dispatched
            long numberofNotesToBeDispatched = requestedAmount / 100;
            if (numberofNotesToBeDispatched > 0)
            {
                if (numberofNotesToBeDispatched > 1)
                {
                    Console.WriteLine(numberofNotesToBeDispatched + " Hundred notes are dispatched by HundredHandler");
                }
                else
                {
                    Console.WriteLine(numberofNotesToBeDispatched + " Hundred note is dispatched by HundredHandler");
                }
            }

            //No Need to Check the Next Handler
        }
    }
}
Step3: Chaining the Handlers

In our example, ATM has managed the sequence in which all the handlers will be chained together. This class is used for internal processing and holding request details. The client is going to use this class. So, create a class file named ATM.cs and copy and paste the following code. In the following code, we are creating four instance variables of our four concrete handlers, and through the constructor, we prepare the sequence of the chain of handlers. We also provide one method (i.e., Withdraw()), which the client will consume.

using System;
namespace ChainOfResponsibilityDesignPattern
{
    // This class managed the sequence in which all the handlers are going to be chained together
    // This class initiates the request to a ConcreteHandler object on the chain
    public class ATM
    {
        private TwoThousandHandler twoThousandHandler = new TwoThousandHandler();
        private FiveHundredHandler fiveHundredHandler = new FiveHundredHandler();
        private TwoHundredHandler twoHundredHandler = new TwoHundredHandler();
        private HundredHandler hundredHandler = new HundredHandler();

        public ATM()
        {
            // Prepare the chain of Handlers
            // Here, we need to set the next handler of each handler
            twoThousandHandler.SetNextHandler(fiveHundredHandler);
            fiveHundredHandler.SetNextHandler(twoHundredHandler);
            twoHundredHandler.SetNextHandler(hundredHandler);
        }

        //The following method handle the request and passes it to the first handler in the chain of responsibility.
        public void Withdraw(long requestedAmount)
        {
            //First check whether the amount is Divisible by 100 or not
            if(requestedAmount % 100 == 0)
            {
                twoThousandHandler.DispatchNote(requestedAmount);
            }
            else
            {
                Console.WriteLine($"You Enter Invalid Amount: {requestedAmount}");
            }
        }
    }
}
Step4: Client

The Main method of the Program class is going to be the Client. So, modify the Main method of the Program class as shown below. As you can see, here we are creating an instance of ATM class and calling the Withdraw method by passing the amount.

using System;
namespace ChainOfResponsibilityDesignPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            ATM atm = new ATM();
            Console.WriteLine("Requested Amount 4600");
            atm.Withdraw(4600);

            Console.WriteLine("\nRequested Amount 1900");
            atm.Withdraw(1900);

            Console.WriteLine("\nRequested Amount 600");
            atm.Withdraw(600);

            Console.WriteLine("\nRequested Amount 750");
            atm.Withdraw(750);

            Console.Read();
        }
    }
}
Output:

Chain of Responsibility Design Pattern in C# with Examples

Chain of Responsibility Design Pattern UML or Class Diagram:

Let us understand the Class Diagram or UML Diagram of the Chain of Responsibility Design Pattern and understand the different components involved. Please have a look at the following image.

Chain of Responsibility Design Pattern UML or Class Diagram

As you can see in the above image, the Chain of Responsibility Design Pattern consists of three components. They are as follows:

  1. Handler: This will be an abstract class that defines how the request will be handled. It contains a member that holds the next handler in the chain and an associated method to set this next handler. It also has an abstract method that concrete handler classes will implement to handle the incoming request, and if required, it will pass the request to the next handler object in the pipeline. In our example, it is the Handler abstract class. The member is NextHandler, the associated method is SetNextHandler, and the abstract method is DispatchNote.
  2. ConcreteHandlerA and ConcreteHandlerB: These will be concrete classes inherited from the Handler abstract class and provide implementations for the abstract method. This method has the logic to handle the request. If required, then it will forward the request to the next handler associated with the pipeline. In our example, it is the DispatchNote method of the TwoThousandHandler, FiveHundredHandler, TwoHundredHandler, and HundredHandler classes.
  3. Client: This class generates the request and passes it to the first handler in the chain of responsibility. In our example, we have simplified this using the ATM class, and the client will call the Withdraw method of the ATM class.
Understanding One Receiver in the Chain to Handles the Request:

Let us understand the Chain of Responsibility Design Pattern with one Receiver Handling the Request with one Real-Time Example. Please look at the following diagram, which shows the reporting hierarchy in a software organization. As you can see, the Developer is reporting to Team Leader. The Team Leader reports to the Project Leader, and the Project Leader reports to HR. Again, the Team Leader can approve leave for a maximum of 10 Days. The Project Leader can approve leave for a maximum of 20 Days, and the HR can approve leave for 30 Days.

Real-Time Examples of Chain of Responsibility Design Pattern

Suppose a developer wants to take a leave of 25 days. So, what the developer will do is he will send a request for 25 days’ leave to the Team Leader. The Team Leader will check whether he can approve the leave or not. As the leave is for 25 days and he can only approve up to 10 days, he will forward the request to the Project Leader.

The Project Leader will check whether he can approve the leave or not. As the leave is for 25 days, the Project Leader will not approve the leave as his capacity is up to 20 days. So, what the project leader will do is he will pass the request to HR, and HR will check and approve the leave.

On the other hand, if the developer is asking for 5 days’ leave, then this can be handled by the Team Leader, and once the Team Leader handles this, he will not forward this request to the Project Leader.

So, the point that you need to remember is once any handler handles the request, it should not forward that request to the next handler. Let’s see the step-by-step procedure to implement the above example using the Chain of Responsibility Design Pattern in C#.

Step1: Creating Abstract Handler

Create a class file named EmployeeLeaveHandler.cs and copy and paste the following code. Here, we created one variable, i.e., Supervisor, to hold the next handler instance, and we initialize this variable through the constructor. We also declare one abstract method, i.e., ApplyLeave, which the Concrete handlers will implement. The following example code is self-explained, so please go through the comment lines for a better understanding.

namespace ChainOfResponsibilityDesignPatternExample
{
    // Handler Abstract Class
    // The Default Chaining Behavior can be implemented inside the abstract handler class.
    public abstract class EmployeeLeaveHandler
    {
        //The Supervisor will hold the reference of the Next Handler
        protected EmployeeLeaveHandler Supervisor;

        //Initializing Supervisor reference using the class constructor
        public void SetNextSupervisor(EmployeeLeaveHandler Supervisor)
        {
            this.Supervisor = Supervisor;
        }

        //The following Method needs to be implemented by the Child handler Classes
        //The following method is going to handle the request.
        public abstract void ApplyLeave(string EmployeeName, int NumberOfDaysLeave);
    }
}
Step2: Creating Concrete Handlers

Now, we are going to create concrete handlers. These will be classes, and they should implement the EmployeeLeaveHandler abstract class and need to provide implementations for the ApplyLeave method.

Team Leader:

First, create a class file named TeamLeader.cs and copy and paste the following code. As you can see here, first, we created one variable, i.e., MAX_LEAVES_CAN_APPROVE, to hold the maximum leave value the Team Leader can approve. This class implements the EmployeeLeaveHandler abstract class and provides the implementation for the ApplyLeave() method. As part of the ApplyLeave method, we check whether the Team Leader can approve the number of leaves the employee applies. If yes, then it is called the ApproveLeave method. If not, then pass the request to the Project Leader. The following example code is self-explained, so please go through the comment lines for a better understanding.

using System;
namespace ChainOfResponsibilityDesignPatternExample
{
    //Concrete Handler 1
    //The following class implement the EmployeeLeaveHandler abstract class and 
    //Provide Implementation for ApplyLeave abstract method
    public class TeamLeader : EmployeeLeaveHandler
    {
        // TeamLeader can only approve up to 10 days of leave
        private readonly int MAX_LEAVES_CAN_APPROVE = 10;

        public override void ApplyLeave(string EmployeeName, int NumberOfDaysLeave)
        {
            //Check if TeamLeader can process this request
            if (NumberOfDaysLeave <= MAX_LEAVES_CAN_APPROVE)
            {
                //ApproveLeave(EmployeeName, NumberOfDaysLeave);
                Console.WriteLine($"TeamLeader Approved {NumberOfDaysLeave} Days Leave for the Employee {EmployeeName}");
            }
            //If TeamLeader can't process the LeaveRequest then pass it on to the supervisor(Project Leader)
            // so that he can process
            else
            {
                Supervisor.ApplyLeave(EmployeeName, NumberOfDaysLeave);
            }
        }
    }
}

Project Leader:

Create a class file named ProjectLeader.cs and copy and paste the following code. As you can see, the MAX_LEAVES_CAN_APPROVE variable holds the maximum leave value the Project Leader can approve. As part of the ApplyLeave method, we check whether the Project Leader can approve the number of leaves the employee applies. If yes, then it is called the ApproveLeave method. If not, then pass the request to HR. The following example code is self-explained, so please go through the comment lines for a better understanding.

using System;
namespace ChainOfResponsibilityDesignPatternExample
{
    //Concrete Handler 2
    //The following class implement the EmployeeLeaveHandler abstract class and 
    //Provide Implementation for ApplyLeave abstract method
    class ProjectLeader : EmployeeLeaveHandler
    {
        // ProjectLeader can only approve up to 20 days of leave
        private readonly int MAX_LEAVES_CAN_APPROVE = 20;

        public override void ApplyLeave(string EmployeeName, int NumberOfDaysLeave)
        {
            //Check if ProjectLeader can process this request
            if (NumberOfDaysLeave <= MAX_LEAVES_CAN_APPROVE)
            {
                Console.WriteLine($"ProjectLeader Approved {NumberOfDaysLeave} Days Leave for the Employee {EmployeeName}");
            }
            //If ProjectLeader can't process the LeaveRequest then pass it on to the supervisor(HR) 
            // so that he can process
            else
            {
                Supervisor.ApplyLeave(EmployeeName, NumberOfDaysLeave);
            }
        }
    }
}
HR:

Create a class file named HR.cs and copy and paste the following code. As you can see, the MAX_LEAVES_CAN_APPROVE variable holds the maximum leave value the HR can approve. As part of the ApplyLeave method, we check whether HR approves the leave. If yes, it calls the ApproveLeave method to approve the leave. If not, then it will print that your leave application is suspended. The following example code is self-explained, so please go through the comment lines for a better understanding.

using System;
namespace ChainOfResponsibilityDesignPatternExample
{
    //Concrete Handler 3
    //The following class implement the EmployeeLeaveHandler abstract class and 
    //Provide Implementation for ApplyLeave abstract method
    public class HR : EmployeeLeaveHandler
    {
        // HR can only approve up to 30 days of leave
        private readonly int MAX_LEAVES_CAN_APPROVE = 30;

        public override void ApplyLeave(string EmployeeName, int NumberOfDaysLeave)
        {
            if (NumberOfDaysLeave <= MAX_LEAVES_CAN_APPROVE)
            {
                Console.WriteLine($"HR Approved {NumberOfDaysLeave} Days Leave for the employee {EmployeeName}");
            }
            else
            {
                Console.WriteLine($"Leave Application Suspended for Employee {EmployeeName}, Please contact HR");
            }
        }
    }
}
Step3: Client

The Main method of the Program class is going to be the Client. Please modify the Main method of your application as shown below. First, we are creating the hierarchy by setting the next level supervisor.

using System;
namespace ChainOfResponsibilityDesignPatternExample
{
    class Program
    {
        static void Main(string[] args)
        {
            TeamLeader teamLeader = new TeamLeader();
            ProjectLeader projectLeader = new ProjectLeader();
            HR hr = new HR();

            teamLeader.SetNextSupervisor(projectLeader);
            projectLeader.SetNextSupervisor(hr);

            teamLeader.ApplyLeave("Anurag", 9);
            Console.WriteLine();

            teamLeader.ApplyLeave("Pranaya", 18);
            Console.WriteLine();

            teamLeader.ApplyLeave("Priyanka", 30);
            Console.WriteLine();

            teamLeader.ApplyLeave("Ramesh", 50);
            Console.Read();
        }
    }
}
Output:

Real-Time Examples of Chain of Responsibility Design Patterns in C#

When to Use Chain of Responsibility Design Pattern in Real-Time Applications?

We need to use the Chain of Responsibility Design Pattern in Real-Time Applications when

  1. A set of handlers are used in the pipeline to handle the request.
  2. Based on certain conditions, you must pass a request to one handler at run-time.
  3. Exception Handling in C# is one of the best examples of the Chain of Responsibility Design Pattern. When an exception is thrown from the try block, then that exception might be handled by a corresponding catch block. Here, you can have more than one catch block. Here, the catch blocks will behave like handlers to handle the exception.

The Chain of Responsibility design pattern can be particularly useful in specific scenarios. Consider using this pattern when:

  • Decoupling is Needed: When the sender of a request should be decoupled from its receiver, Chain of Responsibility offers a way to do this. The sender doesn’t need to know anything about who handles the request.
  • Multiple Objects May Handle the Request: Instead of prescribing a specific handler, the request gets passed along a chain until an object handles it or reaches the end of the chain.
  • Dynamic Handling: If your application requires flexibility in determining which objects handle requests and how they do so, the Chain of Responsibility allows you to assign and change handlers dynamically.
  • Hierarchical Decision Making: In scenarios where decision-making is organized hierarchically (for example, managerial approval processes), this pattern can move a request up the chain until an entity with the appropriate authority handles it.
  • Handling Should be Configurable: If you want your system’s users (or administrators) to dynamically configure how requests are handled or in which order, a Chain of Responsibility can be suitable.
  • Reduce Direct Links Between Objects: If you want to reduce the direct connections between objects to make the system more modular and easier to maintain, this pattern can help.
  • Middleware and Filters: This pattern is commonly used in middleware (like in HTTP request processing), where various tasks like authentication, logging, and data processing are done in a chain.
Real-time Examples of Chain of Responsibility Design Pattern:
  • Event Bubbling in UI: UI systems sometimes use this pattern for event bubbling, where an event on a child element can bubble up to parent elements if not handled.
  • Middleware in Web Frameworks: Many web frameworks use middleware that processes requests in a chain. For instance, in ASP.NET Core, the request pipeline consists of a series of request delegates called one after the other.
  • Logging Systems: As in the example provided, different logging levels (info, warning, error) can be handled by different loggers in a chain.
Drawbacks of Chain of Responsibility Design Pattern:
  • Performance: Passing through a long chain can add overhead.
  • Debugging: If the chain is long or complex, it might be challenging to debug issues since you might need to determine which part of the chain is handling (or not handling) a request.
  • Maintenance: Without careful design, the chain can become a tangled web of interdependencies.

Note: The Chain of Responsibility pattern decouples the sender from the receiver by allowing more than one object to handle a request. It creates a chain of receiver objects to pass the request along until an object handles it.

In the next article, I will discuss the Chain of Responsibility Design Pattern with one Receiver Handling the Request with one Real-Time Example using C#. In this article, I explain the Chain of Responsibility Design Pattern in C# with Examples. I hope you understand the need and use of the Chain of Responsibility Design Pattern Examples in C#.

Leave a Reply

Your email address will not be published. Required fields are marked *