Back to: Design Patterns in C# With Real-Time Examples
Real-Time Examples of Chain of Responsibility Design Pattern
In this article, I am going to discuss the Real-Time Examples of Chain of Responsibility Design Pattern. Please read our previous article where we discussed the Chain of Responsibility Design Pattern in C#. The example that we worked in our previous article is one or more receivers in the chain handles a request. In this article, we are going to discuss an example where only one receiver in the chain will handle the request.
Understanding one receiver in the chain handles the request:
Let us understand this with an example. Please have a 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. Team Leader is reporting Project Leader and Project Leader is reporting to HR. Again the Team Leader can approve a maximum of 10 days leave. The Project Leader can approve leave up to a maximum of 20 Days and the HR can approve leave maximum 30 Days.
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, so 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 so, 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 the 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 Project Leader.
So, the point that you need to remember is once the request is handled by any handler then it should not forward that request to the next handler.
Implementing the Example:
Let see the step by step procedure to implement the above example.
Step1: Creating abstract Handler
Create a class file with the name Employee.cs and then copy and paste the following code in it. Here, we created one variable to hold the next handler instance and we initialize this variable through the constructor. We also declare one abstract method which is going to be implemented by the Concrete handlers.
using System; namespace ChainOfResponsibilityDesignPattern { public abstract class Employee { // next element in chain or responsibility protected Employee supervisor; public void setNextSupervisor(Employee supervisor) { this.supervisor = supervisor; } public abstract void applyLeave(string employeeName, int numberofDaysLeave); } }
Step2: Creating Concrete Handlers
Team Leader:
First, create a class file with the name TeamLeader.cs and then copy and paste the following code in it. As you can here, first we created one variable to hold the maximum leave value the Team Leader can approve. This class implements the Employee abstract class and provides the implementation for the applyLeave() method. As part of the applyLeave method, we check whether the number of leaves the employee applies can be approved by the Team Leader or not. If yes, then, it calls the ApproveLeave method. If not then pass the request to the Project Leader.
using System; namespace ChainOfResponsibilityDesignPattern { public class TeamLeader : Employee { // TeamLeader can only approve upto 10 days of leave private 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); } // if TeamLeader can't process the LeaveRequest then pass on to the supervisor(ProjectLeader) // so that he can process else { supervisor.applyLeave(employeeName, numberofDaysLeave); } } private void ApproveLeave(string employeeName, int numberofDaysLeave) { Console.WriteLine("TeamLeader approved " + numberofDaysLeave + " days " + "Leave for the employee : " + employeeName); } } }
Project Leader:
Create a class file with the name ProjectLeader.cs and then copy and paste the following code in it. As you can here, 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 number of leaves the employee applies can be approved by the Project Leader or not. If yes, then, it calls the ApproveLeave method. If not then pass the request to the HR.
using System; namespace ChainOfResponsibilityDesignPattern { class ProjectLeader : Employee { // ProjectLeader can only approve upto 20 days of leave private 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) { ApproveLeave(employeeName, numberofDaysLeave); } // if ProjectLeader can't process the LeaveRequest then pass on to the supervisor(HR) // so that he can process else { supervisor.applyLeave(employeeName, numberofDaysLeave); } } private void ApproveLeave(string employeeName, int numberofDaysLeave) { Console.WriteLine("ProjectLeader approved " + numberofDaysLeave + " days " + "Leave for the employee : " + employeeName); } } }
HR:
Create a class file with the name HR.cs and then copy and paste the following code in it. As you can here, the MAX_LEAVES_CAN_APPROVE variable holds the maximum leave value the HR can approve. As part of the applyLeave method, we check whether the HR approves the leave or not. If yes, then, it calls the ApproveLeave method which will approve the leave. If not then it will print that your leave application is suspended.
using System; namespace ChainOfResponsibilityDesignPattern { public class HR : Employee { // HR can only approve upto 30 days of leave private int MAX_LEAVES_CAN_APPROVE = 30; public override void applyLeave(string employeeName, int numberofDaysLeave) { if (numberofDaysLeave <= MAX_LEAVES_CAN_APPROVE) { ApproveLeave(employeeName, numberofDaysLeave); } else { Console.WriteLine("Leave application suspended, Please contact HR"); } } private void ApproveLeave(string employeeName, int numberofDaysLeave) { Console.WriteLine("HR approved " + numberofDaysLeave + " days " + "Leave for the employee : " + employeeName); } } }
Step3: Client
Please modify the Main method of your application as shown below. Here, first, we are creating the hierarchy by setting the next level supervisor.
using System; namespace ChainOfResponsibilityDesignPattern { 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:
The task for You:
Please have a look at the following diagram.
As shown in the above image, on the left-hand side we have the quizmaster and on the right side, we have the participants (John, David, and Raj). The Quiz Master will ask some questions. In the chain the first participant is John and John will try to answer the question. If he knows the answer he will answer the question to the quizmaster and will not pass the question to David. But, if he doesn’t know the answer then he will pass the question to the next participant i.e. David. If David knows the answer then David will answer the question to Quizmaster otherwise he will pass the question to Raj. So, the point that you need to remember is at any point in time only one receiver will handle the request and once it handles then it will not pass the request to the next receiver. Please do the above task and submit your code in the comment section.
In the next article, I am going to discuss the State Design Pattern in C# with some examples
namespace ChainOfResponsibility
{
public abstract class QuizMember
{
protected QuizMember nextParticipant;
public void askParticipant(QuizMember participant)
{
this.nextParticipant = participant;
}
public abstract void AskQuestion(string question);
}
}
namespace ChainOfResponsibility
{
public class QuizMaster:QuizMember
{
public override void AskQuestion(string question)
{
nextParticipant.AskQuestion(question);
}
}
}
namespace ChainOfResponsibility
{
public class QuizParticipant: QuizMember
{
private string _name;
public QuizParticipant(string name)
{
_name = name;
}
public bool GetAnswer(string question)
{
Console.WriteLine(“The question is :” + question);
Console.WriteLine(_name + “,do you have answer ?[Y/N]:”);
bool hasAnswer = Console.ReadLine()== “Y”;
if ( hasAnswer)
{
Console.WriteLine(_name +” has the answer “);
}
return hasAnswer;
}
public override void AskQuestion(string question)
{
if (!GetAnswer(question))
{
if (nextParticipant == null)
Console.WriteLine(“Nobody here knows anything”);
else
nextParticipant.AskQuestion(question);
}
}
}
}
namespace ChainOfResponsibility
{
class Program
{
static void Main(string[] args)
{
QuizMaster quizMaster = new QuizMaster();//John, David, and Raj
QuizParticipant participantJohn = new QuizParticipant(“John”);
QuizParticipant participantDavid = new QuizParticipant(“David”);
QuizParticipant participantRaj = new QuizParticipant(“Raj”);
quizMaster.askParticipant(participantJohn);
participantJohn.askParticipant(participantDavid);
participantDavid.askParticipant(participantRaj);
quizMaster.AskQuestion(“How the weather?”);
Console.WriteLine();
quizMaster.AskQuestion(“What time is it now?”);
Console.WriteLine();
quizMaster.AskQuestion(“What is your name?”);
Console.WriteLine();
quizMaster.AskQuestion(“What color is Raj’s underpants?”);
Console.Read();
}
}