This is tutorial is a C++ implementation of the Composite design pattern. This is one of the easier design pattern out there. Sometimes confused with “Prefer composition over Inheritance“. Yes, few people do get confused. In interview.
There is not much to talk about. So I will as usual, jump immediately into the “WHY” followed by the “HOW”.
WHY
To put it simply, it makes dealing with collections easy.
Ever heard of the saying “Everyone is equal in front of Law”?
Something similar going on here. The client does not care if it is an element or a collection of elements. Both are equal in its eyes.
It will just call one method. And wants to be assured that the stuff just works. Whether it called the method on the collection of elements or an individual element does not matter here. This makes client code much simpler.
HOW
What we will do is to make the client talk to an interface as usual. The interface will have some methods. The interface will be implemented by a single element as well as a collection of elements. If there are some methods will do not make sense for an element then we will return something like “Not implemented”. And same for the collection too.
The example here will be very simple. The interface called “IComposite” will have two methods, Display and Add. We will have two classes implement this interface. Class “Single” and “Composite”. We will have a small class class “Node”. The class “Single” will have only one object of kind “Node”. And class “Composite” will have a collection of “Node” objects in it.
Note that since class “Single” is supposed to contain only single object of type “Node”, the Add method in it will return “Not Implemented”.
#include<iostream> #include<vector> using namespace std; class node { int val; public: node(int x) :val(x){} int value()const { return val; } }; class IComposite { public: virtual void Display(void)const = 0; virtual void Add(node* elem){} }; class Single : public IComposite { node* elem; public: Single(node* x) :elem(x){} void Display(void)const { cout << elem->value() << "\n"; } void Add(node* elem) { cout << "Not implemented\n"; } ~Single() { delete elem; } }; class Composite : public IComposite { vector<node*> elems; public: void Display(void)const { for (vector<node*>::const_iterator iter = elems.begin(); iter != elems.end(); ++iter) { cout << (*iter)->value() << "\n"; } cout << "\n"; } void Add(node* elem) { elems.push_back(elem); } ~Composite() { for (vector<node*>::const_iterator iter = elems.begin(); iter != elems.end(); ++iter) { delete *iter; } } }; int main() { node* a = new node(5); node* b = new node(6); node* c = new node(7); IComposite* clientSingle = new Single(a); clientSingle->Display(); clientSingle->Add(b); cout << "\n"; IComposite* clientComposite = new Composite(); clientComposite->Add(b); clientComposite->Display(); clientComposite->Add(c); clientComposite->Display(); return 1; }
And the output is:
As usual I will be pointing out the important lines in this example to make things easier to follow.
- Line 06: This is the small class which will be used as base. It contains a method which just returns the value stored.
- Line 17: The interface. It has two methods, Display and Add.
- Line 24: The class single which implements the interface.
- Line 26: Note that it contains only a single instance of the node class.
- Line 30: The Display method implemented just calls the value function of node to display the contents.
- Line 35: The Add method of Single returns “Not implemented”. This is because by design the class Single will only have a single instance of node inside it. Add is not supported.
- Line 46: The class Composite implementing the interface.
- Line 48: It has a collection of the node elements.
- Line 50: Display method of this class has logic to iterate over the collection and display the value of each element. Note the difference between this implementation and the implementation of this method in the Single class.
- Line 59: Again this method implementation is different compared to the implementation in the Single class. Here the addition of elements is allowed.
- Line 75-86: Notice that the client is working with interface. The calls are made to the interface methods only but the effect is different. In case the object was of class Single, we see that Display method put out a single value. And Add method simply says not implemented. In case the object was of class Composite, the Display method puts out the whole list of the values. And Add method successfully keeps on adding values.
Nicely explained