This is part of a series of posts demonstrating software design patterns using C# and .NET. The patterns are taken from the book Design Patterns by the Gang of Four. Here's the series index page.

What Is This Pattern?

The Chain of Responsibility design pattern seeks to avoid coupling a request to a particular receiver by giving more than one object a chance to handle a particular request.

In essence, we pass an object along a "chain" of potential handlers for that object until one of the handlers deals with the request.

The Rundown

  • Type: Behavioral
  • Useful? 2/5 (Uncommon)
  • Good For: Allowing multiple different objects to possibly process a request.
  • Example Code: On GitHub

The Participants

  • The Handler defines an interface for handling requests.
  • The ConcreteHandler objects can each handle a request, and can access their successor object.
  • The Client initiates the request to a ConcreteHandler object.

A Delicious Example

To model this pattern, let's think about what a restaurant needs to operate and, specifically, how it might get new equipment.

A professional kitchen, showing equipment such as ovens, knives, cutting boards, and ranges. Image is Petrus (London) Kitchen from Wikimedia, used under license.

In a given restaurant, there is probably a hierarchy in which the people who work at that establishment are placed. When a kitchen needs supplies, the Head Chef of that kitchen is likely to be the first one to notice. So, s/he might need to file a purchase request with his/her bosses in order to obtain new equipment, such as knives or cutting boards or even larger items like ovens.

In our kitchen specifically, the purchase request system operates like this:

  1. The Head Chef has implicit approval to purchase any item which is less than $1000 USD.
  2. If the total amount of the purchase is greater than that but less than $2500, the Head Chef must get the restaurant's Purchasing Manager's approval for the purchase.
  3. If the total amount of the purchase is greater than $2500 but less than $10000, then the head chef must get the approval of the restaurant's General Manager to make the purchase.
  4. Finally, if the purchase amount is greater than $10000, the General Manager will call an executive meeting to determine if they need to make the purchase requested.

There's a hierarchy in play here: Head Chef > Purchasing Manager > General Manager. We can model this purchasing system using the Chain of Responsibility design pattern.

Firstly, let's model the object that represents the purchase order itself.

/// <summary>
/// The details of the purchase request.  
/// </summary>
class PurchaseOrder  
{

    // Constructor
    public PurchaseOrder(int number, double amount, double price, string name)
    {
        RequestNumber = number;
        Amount = amount;
        Price = price;
        Name = name;

        Console.WriteLine("Purchase request for " + name + " (" + amount + " for $" + price.ToString() + ") has been submitted.");
    }

    public int RequestNumber { get; set; }
    public double Amount { get; set; }
    public double Price { get; set; }
    public string Name { get; set; }
}

With that in place, let's now write an abstract class Approver which is our Handler participant. This represents any person in the chain who can approve requests.

/// <summary>
/// The Handler abstract class.  Every class which inherits from this will be responsible for a kind of request for the restaurant.
/// </summary>
abstract class Approver  
{
    protected Approver Supervisor;

    public void SetSupervisor(Approver supervisor)
    {
        this.Supervisor = supervisor;
    }

    public abstract void ProcessRequest(PurchaseOrder purchase);
}

Now we can implement our ConcreteHandler objects: one for each person in the chain.

/// <summary>
/// A concrete Handler class
/// </summary>
class HeadChef : Approver  
{
    public override void ProcessRequest(PurchaseOrder purchase)
    {
        if (purchase.Price < 1000)
        {
            Console.WriteLine("{0} approved purchase request #{1}",
                this.GetType().Name, purchase.RequestNumber);
        }
        else if (Supervisor != null)
        {
            Supervisor.ProcessRequest(purchase);
        }
    }
}

/// <summary>
/// A concrete Handler class
/// </summary>
class PurchasingManager : Approver  
{
    public override void ProcessRequest(PurchaseOrder purchase)
    {
        if (purchase.Price < 2500)
        {
            Console.WriteLine("{0} approved purchase request #{1}",
                this.GetType().Name, purchase.RequestNumber);
        }
        else if (Supervisor != null)
        {
            Supervisor.ProcessRequest(purchase);
        }
    }
}

/// <summary>
/// A concrete Handler class
/// </summary>
class GeneralManager : Approver  
{
    public override void ProcessRequest(PurchaseOrder purchase)
    {
        if (purchase.Price < 10000)
        {
            Console.WriteLine("{0} approved purchase request #{1}",
                this.GetType().Name, purchase.RequestNumber);
        }
        else
        {
            Console.WriteLine(
                "Purchase request #{0} requires an executive meeting!",
                purchase.RequestNumber);
        }
    }
}

Notice that each person in the hierarchy (e.g. each link in the chain) can call its own supervisor to make a determination as to whether or not the item can be purchased. This is part of the Chain of Responsibility design pattern: each link is aware of its own successor.

Finally, we need a Client participant, which in this case is our Main().

static void Main(string[] args)  
{
    //Create the chain links
    Approver jennifer = new HeadChef();
    Approver mitchell = new PurchasingManager();
    Approver olivia = new GeneralManager();

    //Create the chain
    jennifer.SetSupervisor(mitchell);
    mitchell.SetSupervisor(olivia);

    // Generate and process purchase requests
    PurchaseOrder p = new PurchaseOrder(1, 20, 69, "Spices");
    jennifer.ProcessRequest(p);

    p = new PurchaseOrder(2, 300, 1389, "Fresh Veggies");
    jennifer.ProcessRequest(p);

    p = new PurchaseOrder(3, 500, 4823.99, "Beef");
    jennifer.ProcessRequest(p);

    p = new PurchaseOrder(4, 4, 12099, "Ovens");
    jennifer.ProcessRequest(p);

    // Wait for user
    Console.ReadKey();
}

Notice that all requests initially flow to Jennifer, the head chef, but if the request's total price is greater than certain amounts then the requets automatically flow to Mitchell the purchasing manager or Olivia the general manager.

The output of this sample project looks like this:

The sample output for the pattern demo app, showing four requests, the last one requiring an executive meeting.

Each request flows through the chain until a link handles it. That's the definition of the Chain of Responsibility Design Pattern!

Will I Ever Use This Pattern?

Rarely. I personally haven't used it at all, but I can see why it would be useful in situations where there's a hierarchy of objects and each one could handle a particular request. But, as always, I'd love to hear about real-world uses of this pattern, so feel free to share in the comments!

Summary

The Chain of Responsibility pattern allows for multiple objects in a chain to make a pass at handling a request object. The request flows through the chain until a link in the chain handles it.

As always, I like to provide code with my tutorials, so the repository for this pattern is over on GitHub and contains all of the sample code used here.

Now I need to go have a talk with Olivia. She never approves my requests. Just because I burnt all the sausages last week doesn't mean I don't need that automatic mini donut factory I asked for! I mean, look at it! It's beautiful!

Happy Coding!

Get My eBook FREE!

Did you enjoy this post? This article and 21 others are also in my free eBook, "The Daily Design Pattern", which you can get just by signing up for my email list.