The Composite design pattern solves the problem via partitioning the various modules of the product.This design pattern treats a combination of objects as if they are an instance of an object. This design pattern sets up a tree structure in which each element performs a specific task. In this pattern every element of a tree can be of composite type which can have child or elements below them or leaf element which can’t have any elements below them. For Design patterns basic explanation see (Design Patterns Simplified Version)
Generic model class diagram of Composite design pattern can be explained as shown in image.
This design pattern has following major components:
1) Component – This class provides the abstraction to all components and declares all the interfaces for the objects needed to be a part of composition.
2) Leaf – This class represents the leaf element in tree structure which implements all component methods.
3) Composite – This class implements methods to manipulate children and it represents a composite component.
Composite Design Pattern Code Example:
Let’s take a very basic example of an organizational hierarchical structure in which all the employees
are divided into workers and managers. Each worker will have a manager while a manager will have several numbers of worker underneath them. Class diagram for the solution of this problem is as shown in image.
Let’s have a look on the Employee class which will act as a component class.
/* Component class */ class Employee { public: Employee(string name, int id): m_name(name), m_id(id) {} void getDetails() { cout<<"Employee NAME: "<<m_name<<" ID: "<<m_id; } string getName() { return m_name; } private: string m_name; int m_id; };
Let’s have a look on the Worker class which will act as Leaf class.
/* Leaf class */ class Worker: public Employee { public: Worker(string manager, string name, int id): Employee(name, id), m_manager(manager) {} void getInfo() { getDetails(); cout<<" Manager Name: "<<m_manager<<endl; } private: string m_manager; };
Now, let’s have a look on the manager class which will act as a Composite class.
/* Composite class */ class Manager: public Employee { public: Manager(string name, int id): Employee(name, id) {} void addReportee(Employee* employee) { l_reportee.push_back(*employee); employee->getDetails(); cout<<" added to Manager Name: "<<getName()<<endl; } void removeReportee(Employee* employee) { list<Employee>::iterator itr; for(itr = l_reportee.begin(); itr != l_reportee.end(); itr++) { if ((*itr).getName() == employee->getName()) { l_reportee.erase(itr); break; } } } void showReportee() { list<Employee>::iterator itr; cout<<"Manager Name: "<<getName()<<" Reportee List"<<endl; for(itr = l_reportee.begin(); itr != l_reportee.end(); itr++) { (*itr).getDetails(); cout<<endl; } } private: list<Employee> l_reportee; };
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() { Employee* w1 = new Worker("Mary","John", 10); Employee* w2 = new Worker("Mary","Rambo", 20); Employee* w3 = new Worker("Mary","Potter", 30); Employee* w4 = new Worker("Lisa","Ron", 40); Employee* w5 = new Worker("Lisa","Messi", 50); Employee* w6 = new Worker("Lisa","Ronaldo", 60); Manager* m1 = new Manager("Mary", 500); Manager* m2 = new Manager("Lisa", 100); m1->addReportee(w1); m1->addReportee(w2); m1->addReportee(w3); m2->addReportee(w4); m2->addReportee(w5); m2->addReportee(w6); m1->showReportee(); m2->showReportee(); m1->removeReportee(w1); m2->removeReportee(w5); m1->showReportee(); m2->showReportee(); delete w1,w2,w3,w4,w5,w6,m1,m2; }
Output of the above given example:
Employee NAME: John ID: 10 added to Manager Name: Mary Employee NAME: Rambo ID: 20 added to Manager Name: Mary Employee NAME: Potter ID: 30 added to Manager Name: Mary Employee NAME: Ron ID: 40 added to Manager Name: Lisa Employee NAME: Messi ID: 50 added to Manager Name: Lisa Employee NAME: Ronaldo ID: 60 added to Manager Name: Lisa Manager Name: Mary Reportee List Employee NAME: John ID: 10 Employee NAME: Rambo ID: 20 Employee NAME: Potter ID: 30 Manager Name: Lisa Reportee List Employee NAME: Ron ID: 40 Employee NAME: Messi ID: 50 Employee NAME: Ronaldo ID: 60 Manager Name: Mary Reportee List Employee NAME: Rambo ID: 20 Employee NAME: Potter ID: 30 Manager Name: Lisa Reportee List Employee NAME: Ron ID: 40 Employee NAME: Ronaldo ID: 60