Back to: Design Patterns in C# With Real-Time Examples
Chain of Responsibility Design Pattern in C#
In this article, I am going to discuss the Chain of Responsibility Design Pattern in C# with examples. Please read our previous article where we discussed the Observer Design Pattern in C# with a real-time example. The Chain of Responsibility Design Pattern falls under the category of Behavioral Design Pattern. As part of this article, we are going to discuss the following pointers.
- What is the Chain of Responsibility Design Pattern?
- Understanding the Chain of Responsibility Design Pattern
- Real-time Example of Chain of Responsibility Design Pattern
- Implementation of Chain of Responsibility Design Pattern in C#
What is the Chain of Responsibility Design Pattern?
According to Gang of Four Definitions, 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 the chain until an object handle 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 then 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 have a look at the following diagram. As shown in the below diagram, on the left side we have a client and on the right side, we have multiple receivers chained together (i.e. receiver 1 has a reference to receiver 2 and receiver 2 has a reference to receiver 3 and so on).
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 or not. 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 then it will send the request to the next receiver (i.e. Receiver 2) in the chain of receivers. If the request does not need any further processing then it will not pass request 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 then it will send the request to the next receiver (i.e. Receiver 2). If it won’t need further processing then it will not pass the request to the next receiver. In this way, the chain of responsibility works.
Real-time Example of Chain of Responsibility Design Pattern:
Let us understand this with an example. Please have a look at the following diagram. As shown in the below image, we have an ATM machine and we have four handlers. The TwoThousandhandler will give 2000 rupees. Similarly, the FiveHundredHandler will give 500 hundred rupees and in the same for 200 and 100 handlers.
Anurag wants to withdraw 4600 rupees from the ATM machine. So, what the ATM machine here 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 is 600 rupees. So, the TwoThousandHandler will send the request to the FiveHundredHandler and the FiveHundredHandler will check the remaining amount and will give one 500 rupees not and the remaining 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 it simply forwards the request to the next handler which is HundredHandler. The HundredHandler check the remaining amount which is 100 and will give one 100 rupees note. In this way, it will handle the request and provide 4600 (2 * 2000, 1*500, and 1*100) to Anurag. This is one of the best examples of one or more receivers in the chain handle the request.
Implementation of Chain of Responsibility Design Pattern in C#:
Let us see the step by step implementation of the Chain of Responsibility Design Pattern in C#.
Step1: Creating Abstract Handler
Please create a class file with the name Handler.cs and then copy and paste the following code in it. Here, you can see that we created one variable of type Handler (i.e. rsHandler) and this variable is going to hold the reference of the next handler. If this is not clear at the moment don’t worry you will understand the need for this variable after a while. This abstract dispatchRs() method is going to be implemented by the concrete handler classes.
namespace ChainOfResponsibilityDesignPattern { public abstract class Handler { public Handler rsHandler; public void nextHandler(Handler rsHandler) { this.rsHandler = rsHandler; } public abstract void dispatchRs(long requestedAmount); } }
Step2: Creating Concrete Handlers
Here we are going to create four handlers (TwoThousandHandler, FiveHundredHandler, TwoHundredHandler, and HundredHandler) to handle the respective currency.
Create a class file with the name TwoThousandHandler.cs and then copy and paste the following code in it. As you can this class inherits from the Handler abstract class and provides the implementation for the abstract dispatchRs method.
using System; namespace ChainOfResponsibilityDesignPattern { public class TwoThousandHandler : Handler { public override void dispatchRs(long requestedAmount) { 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"); } } long pendingAmountToBeProcessed = requestedAmount % 2000; if (pendingAmountToBeProcessed > 0) { rsHandler.dispatchRs(pendingAmountToBeProcessed); } } } }
As part of the dispatchRs() method first, we calculate the number of 2000 notes to be dispatch. If the amount is greater than 1, then we print how many 2000 notes in the console window. Then we check the remaining amount and if the remaining is greater than 0 then we call the dispatchRs() method of the next handler i.e. the FiveHundredHandler.
Implementing FiveHundredHandler:
Create a class file with the name FiveHundredHandler.cs and then copy and paste the following code in it.
using System; namespace ChainOfResponsibilityDesignPattern { public class FiveHundredHandler : Handler { public override void dispatchRs(long requestedAmount) { 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"); } } long pendingAmountToBeProcessed = requestedAmount % 500; if (pendingAmountToBeProcessed > 0) { rsHandler.dispatchRs(pendingAmountToBeProcessed); } } } }
Here, we are also doing the same thing as we did in the previous handler. In a similar way, we need to implement TwoHundredHandler and HundredHandler.
TwoHundredHandler:
Create a class file with the name TwoHundredHandler.cs and then copy and paste the following code in it.
using System; namespace ChainOfResponsibilityDesignPattern { public class TwoHundredHandler : Handler { public override void dispatchRs(long requestedAmount) { 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"); } } long pendingAmountToBeProcessed = requestedAmount % 200; if (pendingAmountToBeProcessed > 0) { rsHandler.dispatchRs(pendingAmountToBeProcessed); } } } }
HundredHandler:
Create a class file with the name HundredHandler.cs and then copy and paste the following code in it.
using System; namespace ChainOfResponsibilityDesignPattern { public class HundredHandler : Handler { public override void dispatchRs(long requestedAmount) { 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"); } } long pendingAmountToBeProcessed = requestedAmount % 100; if (pendingAmountToBeProcessed > 0) { rsHandler.dispatchRs(pendingAmountToBeProcessed); } } } }
Step3: Chaining the Handlers
In our example, ATM has managed the sequence in which all the handlers are going to be chained together. So, create a class file with the name ATM and then copy and paste the following code in it. In the following code, we are creating four instance variables of our four concrete handlers and through the constructor, we preparing the sequence of the chain of handlers. Along with we are also providing one method (i.e. withdraw()) and this method is going to be consumed by the client.
namespace ChainOfResponsibilityDesignPattern { 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 twoThousandHandler.nextHandler(fiveHundredHandler); fiveHundredHandler.nextHandler(twoHundredHandler); twoHundredHandler.nextHandler(hundredHandler); } public void withdraw(long requestedAmount) { twoThousandHandler.dispatchRs(requestedAmount); } } }
Step4: Client
Modify the Main method 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("\n Requested Amount 4600"); atm.withdraw(4600); Console.WriteLine("\n Requested Amount 1900"); atm.withdraw(1900); Console.WriteLine("\n Requested Amount 600"); atm.withdraw(600); Console.Read(); } } }
Output:
The example that we discussed in this article is one or more receivers handle the request.
In the next article, I am going to discuss the real-time example and implementation of one receiver in the chain that handles the request. Here, in this article, I try to explain the Chain of Responsibility Design Pattern in C# step by step with a real-time example. I hope you understood the need and use of the Chain of Responsibility Design Pattern.