Design Patterns Composite
The Composite pattern lets you treat a single object and a group of objects the same way. You build tree-like structures where individual items and containers of items share one interface. Clients work with everything through that shared interface — they never need to check whether they are dealing with one item or many.
Composite belongs to the Structural pattern family. It is the pattern behind file systems, organizational charts, UI component trees, and document structures.
The File System Analogy
A hard drive contains folders and files. A folder can hold files or other folders. When you right-click a folder and choose "Get Size," the computer adds up the sizes of everything inside — files, nested folders, and files inside those nested folders — recursively. You do not care about the internal structure. You call getSize() on one item and get the total.
/Documents ← Folder (Composite)
├── resume.pdf ← File (Leaf) — 120 KB
├── photo.jpg ← File (Leaf) — 3.2 MB
└── /Projects ← Folder (Composite)
├── plan.docx ← File (Leaf) — 45 KB
└── /Archive ← Folder (Composite)
└── old_plan.docx ← File (Leaf) — 38 KB
getSize("/Documents") = 120 KB + 3.2 MB + 45 KB + 38 KB = 3.4 MB
Visual Diagram: Composite Tree
«interface»
Component
+--------------------+
| + getSize(): int |
| + getName(): str |
+--------------------+
▲ ▲
| |
Leaf Composite
+---------+ +---------------------------+
|File | |Folder |
|---------| |---------------------------|
|name | |name |
|size | |children: List[Component] |
|---------| |---------------------------|
|getSize()| |add(c) / remove(c) |
+--------v+ |getSize() → sum of children|
+---------------------------+
Leaf has no children.
Composite holds any mix of Leaves and other Composites.
Key Participants
Component Interface
The common contract for both individual objects and containers. Declares operations that apply to both — such as getSize(), render(), or getName().
Leaf
A single object with no children. It implements the Component interface and does the real work. A file, a button, or a single employee is a Leaf.
Composite
A container that holds a list of Components. Each Component can be a Leaf or another Composite. When the Composite receives a method call, it forwards it to all children and combines the results.
Client
Works through the Component interface. It never checks whether it is dealing with a Leaf or a Composite — it just calls the method and gets the result.
Code Walkthrough in Python
Step 1 — Define the Component Interface
class FileSystemItem:
def get_name(self):
raise NotImplementedError
def get_size(self):
raise NotImplementedError
def display(self, indent=0):
raise NotImplementedError
Step 2 — Create the Leaf
class File(FileSystemItem):
def __init__(self, name, size):
self.name = name
self.size = size
def get_name(self):
return self.name
def get_size(self):
return self.size
def display(self, indent=0):
print(" " * indent + f"📄 {self.name} ({self.size} KB)")
Step 3 — Create the Composite
class Folder(FileSystemItem):
def __init__(self, name):
self.name = name
self.children = []
def add(self, item):
self.children.append(item)
def remove(self, item):
self.children.remove(item)
def get_name(self):
return self.name
def get_size(self):
return sum(child.get_size() for child in self.children)
def display(self, indent=0):
print(" " * indent + f"📁 {self.name} ({self.get_size()} KB)")
for child in self.children:
child.display(indent + 4)
Step 4 — Build the Tree and Use It
root = Folder("Documents")
root.add(File("resume.pdf", 120))
root.add(File("photo.jpg", 3200))
projects = Folder("Projects")
projects.add(File("plan.docx", 45))
archive = Folder("Archive")
archive.add(File("old_plan.docx", 38))
projects.add(archive)
root.add(projects)
root.display()
print(f"Total size: {root.get_size()} KB")
Output
📁 Documents (3403 KB)
📄 resume.pdf (120 KB)
📄 photo.jpg (3200 KB)
📁 Projects (83 KB)
📄 plan.docx (45 KB)
📁 Archive (38 KB)
📄 old_plan.docx (38 KB)
Total size: 3403 KB
How Recursion Powers Composite
root.get_size()
→ resume.pdf.get_size() → 120
→ photo.jpg.get_size() → 3200
→ Projects.get_size()
→ plan.docx.get_size() → 45
→ Archive.get_size()
→ old_plan.docx.get_size() → 38
Archive returns 38
Projects returns 45 + 38 = 83
root returns 120 + 3200 + 83 = 3403
Each Composite asks its children. Children ask their children. The call travels down the tree and values bubble back up. The client calls get_size() once and receives the total automatically.
Real-World Uses of Composite
DOMAIN COMPOSITE EXAMPLE
-------------------------------------------------------
File system Folder contains files and folders
Organization chart Manager contains employees and
other managers
GUI toolkits Panel contains buttons, labels,
and other panels (React, Qt, Swing)
HTML DOM contains , ,
Menu system Menu contains MenuItems and subMenus
Graphics editor GroupShape contains shapes and groups
Bill of materials Assembly contains Parts and assemblies
Composite in a UI Component Tree
Window (Composite)
├── Header (Composite)
│ ├── Logo (Leaf)
│ └── NavBar (Composite)
│ ├── NavItem "Home" (Leaf)
│ ├── NavItem "About" (Leaf)
│ └── NavItem "Contact" (Leaf)
├── Body (Composite)
│ ├── Article (Composite)
│ │ ├── Title (Leaf)
│ │ └── Paragraph (Leaf)
│ └── Sidebar (Composite)
│ └── AdBanner (Leaf)
└── Footer (Leaf)
Call window.render() → renders everything recursively.
Call window.getHeight() → sums heights of all children.
Composite vs Simple Collection
SIMPLE COLLECTION (List) COMPOSITE PATTERN
------------------------------ ---------------------
Holds items of one type. Holds items that can be
Leaves OR Composites.
No hierarchy. Tree hierarchy — depth
can be unlimited.
Client iterates and manages Client calls one method;
items manually. traversal is automatic.
No uniform interface. All nodes share the same
Component interface.
When to Use the Composite Pattern
Use Composite When:
- You need to represent part-whole hierarchies (trees).
- You want clients to treat individual objects and groups identically.
- The depth and shape of the tree is unknown at design time.
Avoid Composite When:
- The hierarchy is flat — just a collection with no nesting. A simple list is cleaner.
- Leaf and Composite objects need very different behavior — the shared interface becomes awkward to maintain.
Advantages and Disadvantages
Advantages
- Clients work with trees of any complexity through one simple interface.
- New component types can be added without changing existing client code.
- Recursive operations (sum, render, find) come naturally from the tree structure.
Disadvantages
- The shared Component interface can force Leaf classes to implement methods that do not apply to them (like
add() or remove()). - Enforcing type constraints at the composite level is harder — a Composite can accidentally accept incompatible children.
Quick Summary
COMPOSITE PATTERN — AT A GLANCE
Problem: You have a tree of objects where individual items
and groups of items need identical treatment.
Solution: Make both Leaves and Composites implement the same
Component interface. Composites forward calls to
their children recursively.
Key idea: Clients see no difference between a Leaf and a
Composite — they call the same methods on both.
Best for: File systems, UI trees, org charts, DOM, menus,
graphics editors, bill of materials.
The Composite pattern eliminates the need to treat groups differently from individuals. Build the tree any way you want — the single interface handles everything, no matter how deep or wide the structure grows.
