Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Chain of Responsibility Design Pattern

4.85/5 (33 votes)
26 Aug 2009CPOL3 min read 70.2K   394  
This article shows a case study about how we can use the Chain of Responsibility Design Pattern.

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:

  1. The parent requests to have a copy of their kid's daily status. (This request can be handled by the teacher herself.)
  2. The parent requests to pay the tuition. (This request needs to be explained by the teacher's manager.)
  3. 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

Chain.JPG

Class Diagram

Image 2

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.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace www.askbargains.com
{
    namespace ChainResponsibility
    {
        //base handler
        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.

C#
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.

C#
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.

C#
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.

C#
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; }
        }

        //Helper Enum
        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.

C#
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)
            {
                //create a teacher
                Teacher aTeacher = new Teacher();
                aTeacher.Name = "Megan";

                //create a manager
                Manager aManager = new Manager();
                aManager.Name = "Susan";

                //create a director
                Director aDirector = new Director();
                aDirector.Name = "Lisa";

                //create the Organizational Chart. (This is Resposiable Chain)
                aTeacher.Boss = aManager;
                aManager.Boss = aDirector;

                //create a request that can be handled by teacher.
                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);
                //send request
                aTeacher.ProcessRequest(firstRequest);
                Console.WriteLine();

                //create a request that can be handled by manager.
                Request secondRequest = new Request();
                secondRequest.Description = "The parent requests to pay the tuition";
                secondRequest.Level = ResponsiableLevel.Medium;
                Console.WriteLine("Request Info: " + secondRequest.Description);
                //send request
                aTeacher.ProcessRequest(secondRequest);
                Console.WriteLine();

                //create a request that can be handled by teacher.
                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);
                //send request
                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!

Chain_Output.JPG

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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)