Behavioral

Chain of responsibility

Purpose

Decouple sender of a request from its receivers by giving multiple objects a chance to handle the request. The request gets passed along a well-defined chain of objects until one of those objects handles the request. 

UML

Behavior

A request issued by the client gets passed along the hierarchy of possible handlers until a concrete handler takes responsibility for handling it.

Example

Assume an application contains Employee, Manager and Department classes (among many others of course), and that each of these classes maintain class-specific information. In the following example, Chain of Responsibility pattern is used to collate information as a request for information is propagated along the chain. For example, a request for information from Employee will obtain information form all three classes, Employee then Manager then Department, as the request is propagated along the chain . A request for information from Manager will obtain information form Manager and Department as the request is propagated along the chain, and so on.

Usage

/* Handler: Defines an interface for handling requests.*/
class InfoHandler
{
// Constructor/Destructor
public:
    InfoHandler( InfoHandler* pIH = 0 ) : pSuccessor(pIH) {}

// Public interface
public:
    virtual void GetInformation( std::string& str)
    {
        if (pSuccessor)
            pSuccessor->GetInformation( str );
    }

// Data members
private:
    InfoHandler* pSuccessor;
};

/* Concrete Handler: Handles requests it is responsible for. Otherwise, it forwards the request to its successor. In this example, Department, Manager and Employee classes are concrete handlers that pass information requests along the following chain; Employee to Manager to Department */
class Application : public InfoHandler
{
// Public interface
public:
    void GetInformation( std::string& str)
    {
        // Application specific code. Write to database, report in a dialog box,
        // etc. Here we just format data.
        str = "Information: " + str;
    }
};

class Department : public InfoHandler
{
// Constructor/Destructor
public:
    Department( InfoHandler* pIH, std::string str ="") : InfoHandler( pIH ), strDeptName(str) {}

// Public interface
public:
    void GetInformation( std::string& str)
    {
        // format data before sending it up the chain
        str = str + strDeptName + ".";
        InfoHandler::GetInformation( str );
    }

// Data members
private:
    std::string strDeptName;
};

class Manager : public InfoHandler
{
// Constructor/Destructor
public:
    Manager( InfoHandler* pIH, std::string str = "") : InfoHandler( pIH ) , strManagerName(str) {}

// Public interface
public:
    void GetInformation( std::string& str)
    {
        // format data before sending it up the chain
        str = str + strManagerName + "/";
        InfoHandler::GetInformation( str ); 
    }
// Data members
private:
    std::string strManagerName;
};

class Employee : public InfoHandler
{
// Constructor/Destructor
public:
    Employee( InfoHandler* pIH, std::string str ="") : InfoHandler( pIH ) , strEmployeeName(str) {}

// Public interface
public:
    void GetInformation( std::string& str)
    {
        // format data before sending it up the chain
        str = str + strEmployeeName + "/";
        InfoHandler::GetInformation( str ); 
    }

// Data members
    std::string strEmployeeName;
};

int main(int argc, char* argv[])
{
    std::string str;

    // Create and connect objects in the following order: Employee, Manager, Department,
    // and Application
    Application *pApp = new Application;
    Department *pDept = new Department( pApp, "R&D" );   // Department forwards to Application
    Manager *pMan     = new Manager( pDept, "Omar" );    // Manager forwards to Department
    Employee *pEmp    = new Employee( pMan, "Ali" );     // Employee forwards to Manager

    // Get information on Manager
    pMan->GetInformation( str );
    std::cout << str << std::endl;         // Information: Omar/R&D.

    // Get information of Manager
    str = "";
    pEmp->GetInformation( str );
    std::cout << str << std::endl;         // Information: Ali/Omar/R&D.

    return 0;
}

Notes