Chain of Responsibility

the Design Pattern

Somewhat relevant image I found

Definition

"the chain-of-responsibility pattern is a design pattern consisting of a source of command objects and a series of processing objects. Each processing object contains logic that defines the types of command objects that it can handle; the rest are passed to the next processing object in the chain."
-- wikipedia

What are command objects?

A command object is a different kind of design pattern. Essentially it is a payload or piece of input data that will be passed around in the Chain of Responsibility pattern.


What are processing objects?

A processing object is an object that takes in the command object, and does something with it. In the context of this pattern, the processing object is analogous link in the "chain"

What is the purpose of this pattern?

The purpose is to

"Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it."
-- some website

What does that mean?

Essentially it means that we may not know which processing objects are supposed to handle a particular command object up front. Using this pattern, we can throw the command object at the list of processing objects and let them figure out what they want to do with them.

Can you show me a picture?

Here, the "Request" is the command object.

How about an example?

Let's say we have a file that has some data in it. We're not sure exactly what kind of data, but we need to parse it into some normalized schema. We have a few different kinds of parsers at our disposal:

  • Tab-delimited parser
  • CSV parser
  • XML parser
  • JSON parser

How do we use the Chain pattern here?

The file, in this case, is our payload or command object, and the parsers are our processing objects. We need to pick a starting processing object, and then link each processing object to the next one in the chain that we want to go down.

Pseudo code

						
// uploaded file; we don't know what kind of data is inside
var file = request.getUploadedFile();

// our first processor; assuming each parser has a common interface or signature
var processor1 = new ProcessingObject(utility.tabParser);

// while instantiating the next processor, we assign it as the "nextProcess" of the previous
var processor2 = processor1.nextProcessor = new ProcessingObject(utility.CsvParser);
var processor3 = processor2.nextProcessor = new ProcessingObject(utility.XmlParser);
var processor4 = processor3.nextProcessor = new ProcessingObject(utility.JsonParser);

// start the chain at processor1, and get a response
var response = processor1.process(file);
						
					

What happens in this code?

  1. We setup the chain, and link together all the processing objects.
  2. Then we start the chain, passing in the file.
  3. It runs through the code in the first processor (TabParser)
    1. if TabParser determines it can process the file, it does so and returns a response.
    2. If not, it sends the file to the nextProcessor, and continues down the chain.

Okay, why not just create an array of parsers and loop through them?

It's mostly about decoupling code. There are better examples than mine.

  • You may want to decouple the starting code from the processing objects as much as possible
  • You may want to give control of continuing the chain to the processing objects
  • The code starting the chain may not know about all of the parsers; might be a single entry point to a third party assembly implementing the pattern.

Other examples: ASP.Net OWIN or Node middleware

These are variations of the Chain of Responsibility pattern that take in HTTP requests (aka command objects). Some of the Chain of Responsibility code happens behind the scenes (like code to start the chain, or link processing objects). Also, in both of these examples, the command object commonly is processed by multiple processing objects.

Node middleware

Many Node frameworks, including Express, use middleware to handle requests. Middleware here is essentially a method that takes three parameters:

req
HTTP Request object (includes querystring, POST params, etc.)
res
HTTP Response object (initially blank, but will contain response status code, response HTML, etc.)
next
A method that lets this middleware method continue the chain to the next middleware method

Node example

						
app.use(function (req, res, next) {
  if (!req.query.pageId) {
    res.status(404); //missing querystring; trigger 404
  } else {
    next();          //everything's fine; carry on
  }
});
						
					

How is this using CoR?

						
app.use(function (req, res, next) {
  if (!req.query.pageId) {
    res.status(404); //missing querystring; trigger 404
  } else {
    next();          //everything's fine; carry on
  }
});
						
					

In this case, the req parameter is the command object or payload. The res parameter could be considered part of the command object, but it's added as a separate parameter for clarity. The next parameter fulfills the same purpose that the nextProcessor property did in our Parser example.

continued

						
app.use(function (req, res, next) {
  if (!req.query.pageId) {
    res.status(404); //missing querystring; trigger 404
  } else {
    next();          //everything's fine; carry on
  }
});
						
					

The idea here is that if the request is missing a querystring parameter, we should return a 404 status request, and NOT continue down the chain. If the parameter exists, we can pass the request down the chain for other middleware to use. What we're not seeing here is the javascript code that initially triggers the chain and links the pieces together.

ASP.Net OWIN

There are several ways to create OWIN middleware, but it lets you create a method that takes in an IDictionary<string, object> object. This object contains properties about the HTTP request and response. ASP.Net OWIN also exposes a next method to continue the chain.

OWIN Example

						
public AppFunc SomeMiddleware(AppFunc next)
{
    // Create and AppFunc using a Lambda expression:
    AppFunc appFunc = async (IDictionary<string, object> environment) =>
    {
        // Do some processing...

        // Invoke and await the next middleware component:
        await next.Invoke(environment);
    };
    return appFunc;
}
						
					

Other considerations

  • The chain should happen in succession, and not in parallel
  • There is the possibility of the command object not being processed - you may need to code up a "catch-all" processing object at the end of the chain
  • In some cases, using the Chain of Responsibility pattern can break the Single Responsibility Principle (each class should have a single responsibility and be encapsulated)
  • It's a somewhat old pattern that may not be as relevant as it once was, at least in it's original form.

Questions?

too bad we're out of time