Complex Decision Making: Chain of Responsibility

This is the last pattern I’m writing up, and it’s one of my favourites.  The chain of responsibility pattern is a brilliant way of dealing with special cases and functional complexity, and it does it in a way that allows you to gain the advantages of hard coding without the disadvantages of inflexibility.  Here’s the basic idea: you have a list of Handlers.  Each has two operations:

  • Do I handle this message?
  • Process the message.

The original GoF statement of chain of responsibility implements the list as a linked list, hence the term “chain”.  This has the advantage of allowing handlers to act upon a message and pass it on, but this is rarely used.

Returning to the example I gave for the visitor pattern, we could implement handlers for executions, allocations and orders.  The chain would run through the list until it found a handler that dealt with the message, it would then dispatch the message to that handler.  The great strength of the pattern is dealing with special cases.  Let’s say that orders for one particular client always come with the price and the amount swapped round.  We can simply add an extremely special case handler that explicitly deals with this.

interface IRule<TValue, TResult> {
    bool Handles(TValue value);
    TResult Handle(TValue value);
}

The principal time that you know you want to use this pattern is when you see large amounts of special case code.  However, it’s also a good way of dealing with excessive generality:

  • Great big XML files
  • Database Decision Tables
  • DSLs

If you find yourself in a situation in which one of these is being proposed, it’s well worth examining whether or not a chain of responsibility would be better.  It can also be used in conjunction with these approaches.  For instance, one handler could be driven off a decision table, with a couple of special cases being handled by other handlers.  This can reduce the complexity of the decision table, so that it only deals with those cases which are easy to generalize.

I haven’t spent a lot of time on this pattern, because my personal experience was that I appreciated how useful it could be as soon as I saw it.

Published by

Julian Birch

Full time dad, does a bit of coding on the side.

Leave a comment