Background
Again, my favorite place - Elizabeth's daycare center.
In my family, my wife and I both need to work everyday; therefore, we drop our kids to the daycare center from 8:00 am to 5:00 pm. I have used my daughter's daycare center as an example scenario in my other articles as well.
In Elizabeth's daycare center, a 1-888-8888-8888 number is used to take all the calls regarding any requests.
To process a request, the teacher in the front desk will answer the phone first; she needs to make the decision whether she can handle the request or not, pushing the request to her supervisor if the decision needs to be made from the upper level.
Three types of requests could be used in this case study:
- The parent requests to have a copy of their kid's daily status. (This request can be handled by the teacher herself.)
- The parent requests to pay the tuition. (This request needs to be explained by the teacher's manager.)
- Dr. WANG requests to schedule a visit for all the kids. (This request needs to be approved by the director.)
Remember, all the requests start by calling the 888 numbers, the front desk teacher takes the call and determines if she could process the request.
Introduction
The Chain of Responsibility Pattern describes how we handle a single request by a chain of multiple handler objects. The request has to be processed by only one handler object from this chain. However, the determination of processing the request is decided by the current handler. If the current handler object is able to process the request, then the request will be processed in the current handler object; otherwise, the current handler object needs to shirk responsibility and push the request to the next chain handler object. And so on and so forth until the request is processed.
Chain of Responsibility Design Pattern Structure
Class Diagram
Implementation Code
Handler Objects
Staff
The Staff
class is our base abstract handler class. It defines the common function (ProcessRequest
) here to allow the child class to implement the details. In this class, a Staff
(Boss
) object is declared to implement our Responsibility Chain.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace www.askbargains.com
{
namespace ChainResponsibility
{
public abstract class Staff
{
public string Name { get; set; }
public Staff Boss { get; set; }
public abstract void ProcessRequest(Request aRequest);
}
}
}
Teacher
In my Teacher
class, I actually code the condition to decide what type of request the teacher can handle. For example: if the request level is not Low
, the teacher needs to push the request to her boss to review it.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace www.askbargains.com
{
namespace ChainResponsibility
{
public class Teacher : Staff
{
public override void ProcessRequest(Request aRequest)
{
if (aRequest.Level != ResponsiableLevel.Low)
{
if (Boss != null)
{
Console.WriteLine("This is {0}. I am a teacher of this daycare." +
" I am not able to process your request. " +
"My boss {1} will review your request",
this.Name, Boss.Name);
Boss.ProcessRequest(aRequest);
}
else
throw new NullReferenceException("No boss assigned");
}
else
{
Console.WriteLine("This is {0}. I am a teacher of this " +
"daycare. Your request has been approved!", this.Name);
}
}
}
}
}
Manager
It is a child class that inherits from Staff
. It has its own condition to check if a request can be processed or be pushed to her boss.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace www.askbargains.com
{
namespace ChainResponsibility
{
public class Manager : Staff
{
public override void ProcessRequest(Request aRequest)
{
if (aRequest.Level != ResponsiableLevel.Medium)
{
if (Boss != null)
{
Console.WriteLine("This is {0}. I am a manager of this daycare." +
" Sorry, I am not able to process your request. " +
"My boss {1} will reivew your request", this.Name, Boss.Name);
Boss.ProcessRequest(aRequest);
}
else
throw new NullReferenceException("No boss assigned");
}
else
{
Console.WriteLine("This is {0}. I am a manager of " +
"this daycare. Your request has been approved!", this.Name);
}
}
}
}
}
Director
The Director
class is the same as the Teacher
and Manager
classes. It will be used as the end of the chain in this case study.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace www.askbargains.com
{
namespace ChainResponsibility
{
public class Director : Staff
{
public override void ProcessRequest(Request aRequest)
{
if (aRequest.Level != ResponsiableLevel.High)
{
if (Boss != null)
{
Console.WriteLine("This is {0}. I am a director of this daycare. " +
"I am not able to process your request. " +
"My boss {1} will reivew your request", this.Name, Boss.Name);
Boss.ProcessRequest(aRequest);
}
else
throw new NullReferenceException("No boss assigned");
}
else
{
Console.WriteLine("This is {0}. I am a director of this " +
"daycare. Your request has been approved!", this.Name);
}
}
}
}
}
Request
The Request
class is a helper class that holds the request information for this demo.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace www.askbargains.com
{
namespace ChainResponsibility
{
public class Request
{
public ResponsiableLevel Level { get; set; }
public string Description { get; set; }
}
public enum ResponsiableLevel
{
Low,
Medium,
High
}
}
}
Client App
From the client side, I create an object each for Teacher
, Manager
, and Director
. I also build the responsibility chain to handle the different requests from the client (Teacher --> Manager --> Director).
From the client side, I also create the three requests and send to the teacher for the screening. Each request has the different levels that will decide who will be the correct handler to process a request.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using www.askbargains.com.ChainResponsibility;
namespace www.askbargains.com
{
namespace Client
{
class Program
{
static void Main(string[] args)
{
Teacher aTeacher = new Teacher();
aTeacher.Name = "Megan";
Manager aManager = new Manager();
aManager.Name = "Susan";
Director aDirector = new Director();
aDirector.Name = "Lisa";
aTeacher.Boss = aManager;
aManager.Boss = aDirector;
Request firstRequest = new Request();
firstRequest.Description = "The parent requests " +
"to have a copy of their kid's daily status";
firstRequest.Level = ResponsiableLevel.Low;
Console.WriteLine("Request Info: " + firstRequest.Description);
aTeacher.ProcessRequest(firstRequest);
Console.WriteLine();
Request secondRequest = new Request();
secondRequest.Description = "The parent requests to pay the tuition";
secondRequest.Level = ResponsiableLevel.Medium;
Console.WriteLine("Request Info: " + secondRequest.Description);
aTeacher.ProcessRequest(secondRequest);
Console.WriteLine();
Request thirdRequest = new Request();
thirdRequest.Description =
"Dr. WANG requests to schedule a visit for all the kids";
thirdRequest.Level = ResponsiableLevel.High ;
Console.WriteLine("Request Info: " + thirdRequest.Description);
aTeacher.ProcessRequest(thirdRequest);
Console.ReadLine();
}
}
}
}
Once you run the client app , all the correspondent handlers will pick up the right request to start processing. Cool!
Conclusion
In this article, I demonstrated how we can use the Chain of Responsibility Pattern to achieve the implementation for a Daycare Request System. I also used the daycare center scenario for the Strategy Design Pattern in my other article.