Table of Contents
What is the Composite Pattern?
The definition of the Composite Pattern from both Design Patterns: Elements of Reusable Object-Oriented Software and Head First Design Patterns: A Brain-Friendly Guide is
The Composite Pattern allows you to compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
Composite Pattern Class Diagram Explained
When looking at the class diagram for the Composite Pattern, we can see there is a common component interface, Component, for accessing our individual objects (Leaf) and composition of objects (Composite). As the definition of the pattern states, this interface allows clients to treat the Leaf and the Composite objects uniformly. This is a common pattern for Menu like design where you would have a common MenuComponent interface with a MenuItem as your Leaf and a Menu or SubMenu representing the Composite object of multiple MenuComponents.
Composite Pattern Example
I decided to demonstrate the Composite Pattern with a Librarian’s Book Collection. So I created a Librarian class that will act as the Client class of the pattern. I wanted to be able to display their book collection, which can include individual books and different book groups (Fiction, Nonfiction, etc). To see the book collection it has a DisplayBookCollection() method. I also created a Book object that will act as the Leaf object of the Composite Pattern and as the Composite class I have BookGroup. Each would be derived from a common abstract base class BookComponent. BookComponent would have empty implementations for an Add and Remove method that BookGroup would override with its own implementation. BookComponent also has an abstract method, DisplayInfo(). The BookComponent allows the BookGroup and Book classes be treated uniformly by its client, Librarian. The class diagram below represents our example’s class relationships.
Example written in C++
So we have our design finished. Let’s take a look and see what our implementation will look like.
BookComponent.h
We can see the BookComponent just has empty implementations for Add() and Remove() whereas DisplayInfo() is abstract left for derived classes to implement.
Book.h
Book.cpp
We can see Book is a simple implementation. It has private members that represent the title and author of a book. DisplayInfo() just prints those private members.
BookGroup.h
BookGroup.cpp
BookGroup has a name and list of BookComponents it’s client modifies via Add() and Remove(). It’s DisplayInfo() implementation prints its name and info from each of the BookComponents in its list.
Librarian.h
Librarian.cpp
The Librarian builds its book collection through its constructor. The construction is a mix of Books and BookGroups that result in a tree like structure. The Librarian class allows clients to view its collection via DisplayBookCollection(). The implementation of this method is as simple as calling DisplayInfo() on its book collection BookComponent member. Since it is the root node of the tree, the result is all of the Books and BookGroups connected.
LibrarianTest.cpp
The LibrarianTest is pretty simple. Just instantiate a Librarian object and request to see its book collection via DisplayBookCollection().
Here is the output of the Librarian test.
Group : Book Collection
Book : Merriam-Webster’s Collegiate Dictionary by Merriam-Webster
Group : Fiction
Group : Kids
Book : Green Eggs and Ham by Dr. Seuss
Group : Kids (Ages 3-5)
Book : Goodnight Moon by Margaret Wise Brown
Group : Nonfiction
Group : Biography
Book : Steve Jobs by Walter Isaacson
All the code for this post can be found here
Benefits of the Composite Pattern
There are a few benefits to using the Composite Pattern. The fact that an individual component and a composite object can be treated uniformly will reduce complexity as the client will not have to make the distinction of each individual component. A second benefit is the addition of new components is easy as it fits nicely into the existing component structure whether it is an individual object or a composite one. The downside to that is you could have trouble restricting composite components to a certain set of individual components and composite components.
Recommended Resources
Here are some resources I recommend for more information on the Composite Pattern
Head First Design Patterns: A Brain-Friendly Guide
Design Patterns: Elements of Reusable Object-Oriented Software
In Closing
There you have it. If you followed along, I hope you now have a better understanding of the Composite Pattern. Please feel free to leave comments and feedback. Much appreciated!