Introduction
The Composite Design Pattern provides a way to create a tree structure that can handle a nested group of items.
For example, the image below shows an application with a main view, sub views and buttons.
Image 1. Application with Views
If we apply a Composite Design Pattern to the application above, we can treat the whole application as a tree-like structure (figure 2).
Image 2 Tree-like structure view
By placing each view in a tree-like structure, we have a unified access point to every view. Furthermore, we can call the same methods on the main view, sub-view or buttons.
For example, we can print the name of every child belonging to the Main View or to Sub-view 1 with the same method call.
Implementing the Composite Design Pattern
We are going to implement an Interface which will contain the following virtual methods:
- add(): Adds a child to the tree
- remove(): Removes a child from the tree
- getChildName(): Prints the name of the node
Listing 1 shows the implementation of the interface named ComponentInterface
Listing 1. Interface implementation
using namespace std;
class Component;
class ComponentInterface{
private:
public:
ComponentInterface(){};
virtual void add(Component *uComponent)=0;
virtual void remove(Component *uComponent)=0;
};
Interfaces are implemented as abstract classes in C++. Interfaces do not provide any method implementation and can not be instantiated. Thus, we need to create a subclass.
Listing 2 shows the implementation of the Component class, a subclass of ComponentInterface.
Listing 2. Component class
class Component:public ComponentInterface{
private:
public:
//1. name of Component
string name;
//2. vector to store all Children
vector<Component*> child;
//3. constructor
Component(string uName);
~Component();
//4. these methods will be implemented by the subclasses
virtual void add(Component *uComponent){};
virtual void remove(Component *uComponent){};
//5. function to print all children name
void getChildName();
};
This subclass contains a vector of type Component (line 2). All children nodes are stored in this vector.
The Component class will not provide a concrete implementation of the add() and remove() methods. Instead, it will delegate this duty to its concrete subclasses (line 4).
Line 5 is a simple method which prints the name of the child node.
Implementing the Window Class
We are going to implement a subclass of the Component class. This class will be called WindowView. This is a concrete class and will implement the add() and remove().
This means that the WindowView class is allowed to have children nodes. You can add and remove as many nodes as you wish.
Listing 3 shows the implementation of the WindowView class. The add() method will store any child node into the vector called child.
Listing 3. WindowView class
void WindowView::add(Component *uComponent){
child.push_back(uComponent);
}
Implementing the Button Class
Finally, we need to implement a subclass of the Component class which acts as a child node. This class is called ButtonView.
As opposed to the WindowView class, the ButtonView class is not allowed to have any children nodes. Therefore, the add() and remove() methods are not implemented in this class.
Composite Design Pattern in action
We are ready to see the Composite Design Pattern in action.
In our main() function, we are going to create three instances of the WindowView class (line 1). These instances are:
- mainScreen
- subScreen1
- subScreen2
In line 2 we are going to create a play and stop button. They are instantiated as ButtonView and will act as children.
In line 3, we make subScreen1 and subScreen2 children of the mainScreen instance.
In line 4, we make the instances play and stop children of the subScreen1 instance.
Now, we want to print the name of all the children that a particular Component instance contains.
In line 5, we print the name of all the children of the mainScreen node. In this case, it will print the name of every child in the tree.
Optionally, we can also print the name of every child of the subScreen1 instance (line 6).
Listing 4 Main.c
int main(int argc, const char * argv[]) {
//1. create Components
Component *mainView=new WindowView("MainView");
Component *subView1=new WindowView("SubView_1");
Component *subView2=new WindowView("SubView_2");
//2. create leaves
Component *playButton=new ButtonView("Play");
Component *stopButton=new ButtonView("Stop");
//3. add children to the root node
mainView->add(subView1);
mainView->add(subView2);
//4. add children to subviews
subView1->add(playButton);
subView1->add(stopButton);
//5. print names of all main-view children
mainView->getChildName();
//6. print names of all subview children
//subView1->getChildName();
return 0;
}
As mentioned above, The Composite Design Pattern provides a way to create a tree structure that can handle a nested group of items.
By placing each view in a tree-like structure, we have a unified access point to every view. Furthermore, we can call the same methods on the main view, sub-view or buttons.
Source code
The source code for the Composite Design Pattern can be found here.
PS. Sign up to my newsletter and get development tips