Chain Of Responsibility

The Chain Of Responsibility Design Pattern

Chain Of Responsibility

Chain of Responsibility

Chain of Responsibility is a behavioural design pattern for passing a request along a chain of possible handlers (or processors) until one of the handlers processes the request. This approach is practical when each variation of an incoming request has one and only one processor. Think of routing in an API: One and only one route can be selected.

 

An alternative interpretation of Chain of Responsibility has each chained processor perform a functionally different action. Uses include the request pipeline for a web services API where the request traverses various processors in a logical order: 

  1. Authenticate the request,
  2. Authorise the request,
  3. Check the cache for a response to the request, 
  4. Deserialise the request payload data, 
  5. Process the request,
  6. and so on.

 

 

That makes sense. Let’s look at a concrete and fun example.

 

Modelling the Executive branch of the US Government 

You can find the code for this example on GitHub as part of my C# Design Pattern repo: https://github.com/olafthielke/DesignPatterns. You’ll find the code in the Patterns project in the Behaviour/ChainOfResponsibility folder. 

 

What if we wanted to model the response of a (very much) simplified US government to a range of incidents? How might we go about that? 

 

We could use the Chain of Responsibility pattern. A practical implementation would give us flexibility regarding which executive officer handles what kind of incident.

 

Note: I know very little about the purpose of the different executive roles within the US government, so I’ve purely used my imagination for the different types of incidents these government officers might handle. :)

 

Say, the incidents come in 4 severity levels: 1 (most serious), e.g. War; 2 (less severe than 1), e.g. Border Skirmish; 3 (less severe, still impactful though), e.g. Tariff Negotiations; and finally, 4 (low severity), e.g. Trade Disputes. 

 

Here is the C# code for a couple of incidents and the abstract Incident base class:

  public abstract class Incident
  {
     public abstract int Severity { get; }
  }
  public class UNResolution : Incident
  {
     public override int Severity => 2;
     public override string ToString() => "UN Resolution";
  }
  public class TariffNegotiation : Incident
  {
     public override int Severity => 3;
     public override string ToString() => "Tariff Negotiation";
  }

The Severity overrides are critical, while the ToString() overrides exist merely to log the incident names easily. 

 

So far, so good. What about the handlers? These don’t know about each other. All but one of the handlers has a superior that they can escalate the incident to. The President is the handler of last resort; no escalation is possible from here. 

  public class ThePresident : IHandler
  {
     public override string ToString() => "The President";

     public void Handle(Incident incident)
     {
        Console.WriteLine($"{this} handles {incident}. The Buck stops here.");
     }
  }

IHandler interface:

  public interface IHandler
  {
     void Handle(Incident incident);
  }

The President handler must be able to deal with all incidents that make it through to them. No worries, though, The President has preceding officers who handle all incidents appropriate to their level.

 

For example, here is the listing for the TradeRepresentative, a lowly handler for Severity 4 incidents:

  public class TradeRepresentative : EscalatingHandler
  {
     public override string ToString() => "Trade Representative";

     public TradeRepresentative(IHandler superior)
        : base(superior)
     { }

     public override void Handle(Incident incident)
     {
        if (incident.Severity == 4)
        {
           LogCanHandle(incident);
           // TODO: Code to handle this level of severity incident.
        }
        else
        {
           LogCannotHandle(incident);
           // Escalate to superior!
           Escalate(incident);
        }
     }
  }

 

EscalatingHandler is the base class for all handlers that can escalate further up the chain of command. So all officer types other than ThePresident derive from this abstract class: 

  public abstract class EscalatingHandler : IHandler
  {
     protected IHandler Superior { get; set; }

     protected EscalatingHandler(IHandler superior)
     {
        Superior = superior;
     }

     public virtual void Escalate(Incident incident)
     {
        Superior.Handle(incident);
     } 

     public abstract void Handle(Incident incident);

     public void LogCanHandle(Incident incident)
     {
        Console.WriteLine($"{this} handles {incident}.");
     }

     public void LogCannotHandle(Incident incident)
     {
        Console.WriteLine($"{this} doesn't handle {incident}. => Escalate.");
     }
  }

Nice!

Before we launch different incident types at this chain of command, we must first set up a chain of command! And only then are we ready to find out which handlers will take care of which incidents:

  private static void RunChainOfResponsibility()
  {
     // Setup Chain of Responsibility
     var handler = new TradeRepresentative(
        new Undersecretary(
           new ChiefOfStaff(
              new ThePresident())));

     Console.WriteLine("Trade Dispute (Severity 4):");
     handler.Handle(new TradeDispute());
     Console.WriteLine("----------------------------------------------");
     Console.WriteLine();

     Console.WriteLine("Tariff Negotiation (Severity 3):");
     handler.Handle(new TariffNegotiation());
     Console.WriteLine("----------------------------------------------");
     Console.WriteLine();

     Console.WriteLine("Border Skirmish (Severity 2):");
     handler.Handle(new BorderSkirmish());
     Console.WriteLine("----------------------------------------------");
     Console.WriteLine();

     Console.WriteLine("UN Resolution (Severity 2):");
     handler.Handle(new UNResolution());
     Console.WriteLine("----------------------------------------------");
     Console.WriteLine();

     Console.WriteLine("War (Severity 1):");
     handler.Handle(new War());
  }

I’ve used constructors to set up the decoupled chaining between the various processors. However, I could have achieved the same result via a public method called SetSuccessor() or a Successor setter property. 

 

And the results:

Handled incidents

 

As we can see, handlers not authorised to process incidents escalate to their superiors in the chain of command, even though they are unaware of who that might be. Any incident not managed by someone falls through to The President. 

 

I hope this example demonstrates the usefulness of the Chain of Responsibility design pattern. Please consider Chain of Responsibility (or the Strategy pattern) next time you must process a request, and one or more processors are available. 

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply