Chain of Command Design Pattern


Table of Contents 

Intent
"Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handel the requiest. Chain the receiving objects and pass the request along the chain until an object handles it."(Gamma, Helm, Johnson, Vlissides, 1994, p. 223)

Motivation
  • Decouple senders and receivers
  • The object that made the request has no explicit knowledge of who will handle it. (Implicit Receiver)
  • Give multiple objects a chance to handle the request 


In order to forward the event or message along the chain, each element or class in the chain must share a common interface for:

  • handling requests and
  • accessing its successor on the chain.

Figure 1 - Example Class Diagram (UML)

In the example class diagram above, the helpHandler parent class optionally handles the access to the successor by a call in the concrete handlers to Handler::HandleHelp()

Example

Figure 2 - Interaction Diagram for Example.


Applicability

Use the Chain of Responsibility when:

(Gamma et al, 1994, p.225)

  • More than one object may handle a request,
  • handler isn't known a priori,
  • the handler should be ascertained automatically,
  • it is desired to issue the request to one of several objects without specifying the receiver explicitly, and
  • the set of objects that can handle a request should be specified dynamically

Structure

Figure 3 - Typical Structure of a Chain of Responsibility


Participants 

Handler  

  • Abstract class or mixin (C++ term)
  • Defines an interface for handling requests
  • (optional) implements the successor link.

Concrete Handler 

  

  • Handles requests it is responsible for
  • Can access successor

The logic is simple:

  1. If the concrete handler can fulfill the request, then it does so.
  2. If the concrete handler cannot fulfill the request, then it passes the request on to it's successor if a successor exists.

Client

Simply initiates the request to a ConcreteHandler in the chain.

Collaborations
The collaborations in a Chain of Responsibility design pattern are obvious. The request propogates along the chain until a handler object takes responsibility for handling it.
 

Consequences 

Benefits 

Coupling is reduced

  • sender object and receiver objects have no explicit knowledge of each other.
  • objects have no knowledge as to the overall structure 

Flexibility in assigning responsibilities to objects

  • dynamically change the chain at run-time.
  • subclassing will specialize the handlers at compile time.

Liabilities

Handling isn't guaranteed

  • since there is low coupling, there is no absolute guanantee that the request will be handled.
  • the request can fall off the end of the chain without being handled.
  • 2 new opportunities for software errors
    • chain is not configured properly therefore the request is not handled
    • circular chain could produce and infinite loop

Implementation Issues 

Successor Chain  

According to Gamma et al (1994), there are two ways of implementing the successor chain

Definition of new links or use of existing links.

Using existing links work when the links reflect the chain of responsibility your application requires.

An example might be found in structures that define such a hierarchy (Composite). In the case of a Composite, the parent is the successor. See discussion section at the end of this page for questions on the use of the composite patter and existing hierarchies.


 Figure 4 - Basic Composite structure

Connecting successors

If no existing references exist then the links will need to be defined. If this is the case then the top-level Handler can maintain the successor as well as define the interface. The Handler then provides the default method to forward requests on to the successor. This allows the ConcreteHandler subclasses to basically ignore the interface method unless it wishes to override the method.

C++ Example

(Gamma et al, 1994, p.227)

class helpHandler {

public :

HelpHandler (HelpHandler* s) : _successor(s) { }

virtual void HandleHelp();

private:

HelpHandler* _successor;

};

void HelpHandler::HandleHelp () {

if (_successor) {

_successor->HandleHelp();

}

}

Representing requests

  1. Hard-coded operation invocation
  2. Single method that accepts a request (object, code, string, etc)
  • Pros
    • Interface needs to be defined by requestor and receiver
    • more flexible
    • open-ended
  • Cons
    • requires additional conditional statements (increased complexity)
    • not type safe

Can use a Request class to bundle request parameters.(Command Pattern related?)


Sample Code (Gamma et al, 1994, pp. 229-232)

UML Model

Figure 5 - UML Model of HelpHandler Chain of Responsibility example.


Abstract Class HelpHandler  

typedef int Topic;

const Topic NO_HELP_TOPIC = -1;

class HelpHandler {

public:

HelpHandler (HelpHander* = 0, Topic = NO_HELP_TOPIC);

virtual bool HasHelp();

virtual void SetHandler(HelpHandler*, Topic);

virtual void HandlerHelp();

private

HelpHandler* _successor;

Topic _topic

};


HelpHandler::HelpHandler (helpHandler* h, Topic t) : _successor(h), _topic(t) { }


bool HelpHandler::HasHelp() {

return _topic != NO_HELP_TOPIC;

}


void HelpHander::HanldeHelp() {

if (_successor != 0) {

_successor->HanldeHelp();

}

}


 

Abstract Class Widget 

class Widget : public helpHandler {

protected:

//Constructor

Widget(Widget* parent, topic t = NO_HELP_TOPIC);

private:

Widget* _parent;

};

Widget::Widget (Widget* w, Topic t) : HelpHander (w,t){

_parent = w;

}

Button Class

class Button : public Widget {

public:

Button(Widget* d, Topic t = NO_HELP_TOPIC);

Button::Button (Widget* h, Topic t) : Widget(h,t) {}

void Button::HandleHelp () {

if (HasHelp()) {

// Whatever help there is

} else {

HelpHandler::HandleHelp();

}

}

Dialog Class

class Dialog : public Widget {

public:

Dialog(HelpHandler* h, Topic t = NO_HELP_TOPIC);

virtual void HandleHelp();

};


Dialog::Dialog (HelpHandler* h, Topic t) : Widget(0) {

SetHandler (h,t);

}


void Dialog::HandleHelp() {

if (HasHelp()) {

// Whatever help there is

} else {

HelpHandler::HanldeHelp();

}

}

Application Class

class Application : public helpHandler {

public:

Application(Topic t) : HelpHandler(0,t) {}

virtual void HandleHelp();

};


void Application::HandleHelp() {

// Whatever Help is here

}


Known uses 

User Events 

MacApp, ET+ (Event Hander)

Symantec TCL (Bureaucrat)

NeXT AppKit (Responder)

Graphics  

Unidraw

ET++

Related patterns

Composite


Figure 6 - Composite Design Pattern



Disscussion Items/Questions
  1. Can you have a Chain of Responsibility where more that one object needs to handle the request? In other words, do more that one object need to know about an event or handle the event? (Observer?)
  2. How is a dispatch different from a Chain of Responsibility?
  3. What about a tree structure instead of a direct chain?
  4. Should there be a contoller for a chain of responsibility instead of the Handler? i.e. the controller would make the chain while the default handler method would call the controller which would be the object that knows who the next in the chain would be. Controller would ensure that the request was handled -> could provide an error handler for requests dropping off the end.

 


References   
Gamma, E., Helm, R., Johnson, R. & Vlissides, J. (1995). Design Patterns: Elements of Reusable Object-Oriented Software. Reading Mass., Addison Wesley. 
  Pree, W. (1995). Design Patterns for Object-Oriented Software Development. Reading Mass, Addison-Wesley.