Chain of responsibility pattern

1. Usage

  • 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. [GoF, p223]
  • Launch-and-leave requests with a single processing pipeline that contains many possible handlers.
  • An object-oriented linked list with recursive traversal.

2. UML class diagram

Chain of Responsibility
Chain of Responsibility
Chain of Responsibility

3. Pros

  • Decouples the sender of the request and its receivers.
  • Simplifies your object as it doesn’t have to know about the chain structure and keep direct references to its members.
  • Allows you to add or remove responsibilities dynamically by changing the members or order of the chain.

4. Cons

  • Hard to observe the run-time characteristics and debug

5. Source code


// From http://cpp-reference.ru/patterns/behavioral-patterns/chain-of-responsibility/
#include <iostream>
#include <vector>
#include <ctime>
using namespace std;
 
class Base
{
    // 1. Указатель "next" в базовом классе
    Base *next;
  public:
    Base()
    {
        next = 0;
    }
    void setNext(Base *n)
    {
        next = n;
    }
    void add(Base *n)
    {
        if (next)
          next->add(n);
        else
          next = n;
    }
    // 2. Метод базового класса, делегирующий запрос next-объекту
    virtual void handle(int i)
    {
        next->handle(i);
    }
};
 
class Handler1: public Base
{
  public:
     /*virtual*/void handle(int i)
    {
        if (rand() % 3)
        {
            // 3. 3 из 4 запросов не обрабатываем
            cout << "H1 passsed " << i << "  ";
            // 3. и делегируем базовому классу
            Base::handle(i);        }
        else
          cout << "H1 handled " << i << "  ";
    }
};
 
class Handler2: public Base
{
  public:
     /*virtual*/void handle(int i)
    {
        if (rand() % 3)
        {
            cout << "H2 passsed " << i << "  ";
            Base::handle(i);
        }
        else
          cout << "H2 handled " << i << "  ";
    }
};
 
class Handler3: public Base
{
  public:
     /*virtual*/void handle(int i)
    {
        if (rand() % 3)
        {
            cout << "H3 passsed " << i << "  ";
            Base::handle(i);
        }
        else
          cout << "H3 handled " << i << "  ";
    }
};
 
int main()
{
  srand(time(0));
  Handler1 root;
  Handler2 two;
  Handler3 thr;
  root.add(&two);
  root.add(&thr);
  thr.setNext(&root);
  for (int i = 1; i < 10; i++)
  {
    root.handle(i);
    cout << '\n';
  }
}

Leave a Reply

Your email address will not be published. Required fields are marked *