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

Cooking
Alright, who ordered the licorice sauce?! Photo by Cater Yang / Unsplash

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

NOTE: This post is part of a series demonstrating software design patterns using C# and .NET.  The patterns are taken from the book Design Patterns by the Gang of Four. Check out the other posts in this series!

The Rundown

  • Type: Behavioral
  • Useful? 2/5 (Uncommon)
  • Good For: Allowing multiple different objects to possibly process a request.
  • Example Code: On GitHub
exceptionnotfound/DesignPatterns
Repository for all of my Daily Design Pattern posts. - exceptionnotfound/DesignPatterns
Project for this post: ChainOfResponsibility

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.
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, she or 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 pattern.

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

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

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!