You can see this and other great articles on design patterns here.

The chain of responsibility pattern allows you to pass a request to from an object to the next until the request is fulfilled. For example, you can pass a mortgage application request to a bank manager, and if the manager cannot approve the loan, it can be passed to his supervisor and so on. The chain of responsibility automates the passing of requests from one object to the next.

The logic of the pattern is analogous to the exception handling routine in the compiler. When an exception happens, it is passed to the next catch statement until it is matched to an exception type where it will be handled.  

Let's look at the UML  of the chain of responsibility pattern first, then we will look at an example to see how it works. Below is the UML of the Chain of Responsibility pattern

  • The Handler class is the parent abstract class for all the objects that can handle requests:
    • The protected nextHandler variable is a reference that points to the next handler. If the request cannot be processed by the object it will be passed to the nextHandler for processing.
    • The SetNextHandler method simply assigns the nextHandler variable.
    • The ProcessRequest method is the method signature that all child classes must implement.
  • The ConcreteHandler are the concrete child classes that handles the requests. In its ProcessRequest method it checks to see if it can process the request, if yes it will process the request and return, if not the request will be passed to the next handler. This logic is repeated until the request is fulfilled.

Let's apply the pattern to an example. In a bank where the approval route for mortgage applications are from the bank manager to the director then to the vice president, where the approval limits are:

  • Manager – 0 to 100k
  • Director – 100k to 250k
  • Vice President – anything above 250k

We will pass the request to the manager until the application is processed. The UML for the example will be:

The client code can then be:

LoanApprover a = new Manager();

LoanApprover b = new Director();

LoanApprover c = new VicePresident();

a.SetNextApprover(b);

b.SetNextApprover(c);

a.ApproveLoan(new Loan(50000));  //this will be approved by the manager

a.ApproveLoan(new Loan(200000));  //this will be approved by the director

a.ApproveLoan(new Loan(300000));  //this will be approved by the vice president

Below are the implementation code and the output of our example. Notice that the request is automatically processed by the correct person without the client code having to determine who will process the request:

class Program
    {
        static void Main(string[] args)
        {
            LoanApprover a = new Manager();
            LoanApprover b = new Director();
            LoanApprover c = new VicePresident();
            a.SetNextApprover(b);
            b.SetNextApprover(c);
            a.ApproveLoan(new Loan(50000));  //this will be approved by the manager
            a.ApproveLoan(new Loan(200000));  //this will be approved by the director
            a.ApproveLoan(new Loan(500000));  //this will be approved by the vice president
        }
    }

    abstract class LoanApprover
    {
        protected LoanApprover nextApprover;

        public void SetNextApprover(LoanApprover nextApprover)
        {
            this.nextApprover = nextApprover;
        }

        public abstract void ApproveLoan(Loan i);
    }

    class Manager : LoanApprover
    {
        public override void ApproveLoan(Loan i)
        {
            if (i.Amount <= 100000)
                Console.WriteLine("Loan amount of " + i.Amount + " approved by the Manager"); 
            else
                nextApprover.ApproveLoan(i);
        }
    }

    class Director : LoanApprover
    {
        public override void ApproveLoan(Loan i)
        {
            if (i.Amount <= 250000)
                Console.WriteLine("Loan amount of " + i.Amount + " approved by the Director"); 
            else
                nextApprover.ApproveLoan(i);
        }
    }

    class VicePresident : LoanApprover
    {
        public override void ApproveLoan(Loan i)
        {
            Console.WriteLine("Loan amount of " + i.Amount + " approved by the Vice President"); 
        }
    }

    public class Loan
    {
        private int amount;

        public int Amount
        {
            get { return amount; }
        }

        public Loan(int amount)
        {
            this.amount = amount;
        }
    }

Liked this article? You can see this and other great articles on design patterns here.

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架