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
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'; } }