The Chain-of-Responsibility design pattern basically consists of a source of command objects and a hierarchical series of processing objects. Every processing unit will process only typical kind of commands and it will pass rest of the command to next processing unit, thus creating a chain of processing units and that’s why the name of this design pattern is Chain-of-Responsibility pattern. This pattern provides the idea of one of the best programming practice which is “loose coupling”. For Design patterns basic explanation see (Design Patterns Simplified Version).
Generic model class diagram of Chain-of-Responsibility design pattern is as shown in image.
In this design pattern basically any request is passed through a chain of objects until unless one of the chained objects finally handles it. This design pattern should be used in cases where multiple objects can handle a command and selection of a handler is automatically chosen in dynamic way.
Chain-of-Responsibility Design Pattern Code Example:
Let’s take an example of any organization where employees are categorized into hierarchical groups like labour, supervisor, Manager etc, where every one has a set of responsibilities to perform. For eg: Labours will be questioned for the work done whereas Supervisor will be questioned about the team’s performance whereas Manager will be questioned about the department’s performance. Class diagram for the solution of above problem is as shown in below image.
Let’s have a look on the class definition of all Staff classes.
class Query; //Forward declaration /* Abstract Class */ class Staff { private: string m_name; Staff* m_boss; public: Staff(string name) { m_name = name; } virtual void HandleQuery(Query q) = 0; virtual string getName() { return m_name; } virtual Staff* getBoss() { return m_boss; } virtual void setBoss(Staff* boss) { m_boss = boss; } }; class Labour:public Staff { public: Labour(string name): Staff(name) {} virtual void HandleQuery(Query q) { if(q.getLevel() == LOW) { cout<<"Question Asked is: \""<<q.getQuestion()<<"\" is answered by "<<getName()<<endl; return; } cout<<"This is "<<getName()<<". Sorry I am unable to process your request. My Boss: "<< getBoss()->getName()<<" will process this request"<<endl; getBoss()->HandleQuery(q); } }; class Supervisor:public Staff { public: Supervisor(string name): Staff(name) {} virtual void HandleQuery(Query q) { if(q.getLevel() == MEDIUM) { cout<<"Question Asked is: \""<<q.getQuestion()<<"\" is answered by "<<getName()<<endl; return; } cout<<"This is "<<getName()<<". Sorry I am unable to process your request. My Boss: "<< getBoss()->getName()<<" will process this request"<<endl; getBoss()->HandleQuery(q); } }; class DepartmentHead:public Staff { public: DepartmentHead(string name): Staff(name) {} virtual void HandleQuery(Query q) { if(q.getLevel() == HIGH) { cout<<"Question Asked is: \""<<q.getQuestion()<<"\" is answered by "<<getName()<<endl; return; } cout<<"This is "<<getName()<<". Sorry We are unable to process your request" <<endl; } };
Now, Let’s have a look on the query class which will store the query and it’s severity.
enum queryLevel_e{LOW, MEDIUM, HIGH}; class Query { private: queryLevel_e m_level; string m_question; public: Query(string question, queryLevel_e level): m_question(question), m_level(level) {} queryLevel_e getLevel() { return m_level; } string getQuestion() { return m_question; } };
Let’s see now how to use the above described classes to build the final product. Below code is sample “main” function code.
int main() { Labour l("Wayne Rooney"); Supervisor s("Ryan Giggs"); DepartmentHead d("Sir Alex Ferguson"); l.setBoss(&s); s.setBoss(&d); d.setBoss(NULL); Query q1("can you finish the work?", LOW); Query q2("Can the team finish up the work on time?", MEDIUM); Query q3("Can the production department meets the target?", HIGH); l.HandleQuery(q1); l.HandleQuery(q2); l.HandleQuery(q3); }
Output of the above given example:
Question Asked is: "can you finish the work?" is answered by Wayne Rooney This is Wayne Rooney. Sorry I am unable to process your request. My Boss: Ryan G iggs will process this request Question Asked is: "Can the team finish up the work on time?" is answered by Rya n Giggs This is Wayne Rooney. Sorry I am unable to process your request. My Boss: Ryan G iggs will process this request This is Ryan Giggs. Sorry I am unable to process your request. My Boss: Sir Alex Ferguson will process this request Question Asked is: "Can the production department meets the target?" is answered by Sir Alex Ferguson