The Composition design pattern helps you unify individual objects and nested objects.
Here is one use case for the composition design pattern.
Meet Frank
A man named F. Frank decides to write an autobiography of himself. His book is rather strange; he writes a few chapter in the book that consists of subsections, kind of like a textbook. But Frank acknowledges that he himself is a strange guy, and he wants to sell the book as it is.
He calls the book "The Autobiography of F. Frank".
This is what he has so far on his book's table of contents:
- Preface
- Introduction
- Chapter 1: Friends
- Pink Guy
- Dade
- Chapter 2: Enemies
- Chapter 3: Trials and Tribulations
- Frank faces the dark lord
- Training in the mountains
- Fiesta
- Warzone
Note how Chapter 2 doesn't have any sub-chapters, and Chapter 3's sub-chapter "Training in the mountains" has a mini-chapter. What is Frank thinking? Who knows.
Moving on, Frank decides that he wants his table of contents publicized on the world wide web, with detailed synopses of each chapter. He looks up some object oriented design ideas on the web and starts with the following.
class Entry(object):
"""
An entry in the table of contents
"""
def __init__(self, name, summary):
self.name = name
self.summary = summary
class Chapter(Entry):
subchapters = []
def add_subchapter(self, subchapter):
self.subchapters.append(subchapter)
class ChapterTitle(Entry):
pass
Here, we see 3 classes. We have an Entry
class, that represents each entry in the table of contents.
Next, we see the Chapter
class and the ChapterTitle
class.
Why did Frank define both Chapter
and ChapterTitle
to be classes that inherit from Entry
? Chapter
and ChapterTitle
sounds awfully similar to each other, but Frank disagrees. Frank's reasoning is as follows:
F. Frank: "The Chapter class can have 1 or more Chapter Titles or Chapters. Yeah, you know, it's like that movie, Inception."
So, according to what Frank says, we can visualize his table of contents in this manner:
- Preface (ChapterTitle)
- Introduction (ChapterTitle)
- Chapter 1: Friends (Chapter)
- Pink Guy (ChapterTitle)
- Dade (ChapterTitle)
- Chapter 2: Enemies (ChapterTitle)
- Chapter 3: Trials and Tribulations (Chapter)
- Frank faces the dark lord (ChapterTitle)
- Training in the mountains (Chapter)
- Fiesta (ChapterTitle)
- Warzone (ChapterTitle)
Note how Chapter 1 and Chapter 3 is a different class compared to Chapter 2. Chapter 3 also has a nested Chapter (a Chapter in a Chapter).
Composition
We can now see that the Chapter
class is just a collection or aggregate of ChapterTitle
s.
Frank wants to design a class now, called TableOfContents
that houses a list of Chapter
objects or ChapterTitle
objects. But storing a list of entries isn't enough; Frank wants the TableOfContents
class to be smart enough to know how to handle a Chapter
or a ChapterTitle
when needed. Maybe a print_contents()
method can be defined, which iterates over all of the entries, regardless of what class it is (why should it matter if it's a Chapter
or a ChapterTitle
, a Table of Contents class should print every entry there is!).
...
And it came to Frank right then and there. The design pattern he wants to use is the Composite pattern.
Definition
Directly from Wikipedia:
The composite pattern describes a group of objects that is treated the same way as a single instance of the same type of object.
The Composite pattern is basically used to represent objects like a tree (in particular, a computer science tree).
In a tree, there is a root node, and each child can also be a tree itself. On one hand, a child node with no offsprings is a leaf, which is identical to ChapterTitle
. On another hand, a child node with several offsprings (a child with children) is basically another tree, which is identical to Chapter
.
It then follows that the Chapter
class is recursive in nature because it can have a child that is a Chapter
itself, or a ChapterTitle
.
When to use
Composite should be used when clients ignore the difference between compositions of objects and individual objects. If programmers find that they are using multiple objects in the same way, and often have nearly identical code to handle each of them, then composite is a good choice.