Composite
Treat a single item and a whole tree of items the same way, so client code never asks "is this a leaf or a group?"
Big idea
Composite lets you build trees where leaves and groups share one interface. A file and a folder both answer size(); a folder answers by asking its children and adding up. Client code calls size() on whatever it holds and the recursion takes care of itself.
The problem it solves
You need the total size of a directory. Without Composite:
def total(node):
if isinstance(node, File):
return node.bytes
elif isinstance(node, Folder):
return sum(total(c) for c in node.children)
Every operation — size, count, search, render — repeats this type switch, and a new node type (a symlink, a zip archive) means editing all of them.
Think of it like
An army's chain of command, or a company budget. Ask the CEO for headcount and she asks her directors, who ask their managers, who count their teams. Each person answers the same question the same way — "my people plus everyone under them" — and the person asking doesn't care how deep it goes.
Structure
- Component (
Node) — the shared interface. - Leaf (
File) — does the work itself. - Composite (
Folder) — holds children and delegates to them, combining results.
In code
class File:
def __init__(self, name, size):
self.name, self._size = name, size
def size(self):
return self._size
def render(self, indent=0):
return f"{' ' * indent}{self.name} ({self._size})"
class Folder:
def __init__(self, name, *children):
self.name, self.children = name, list(children)
def add(self, node):
self.children.append(node)
return self
def size(self):
return sum(c.size() for c in self.children) # recursion via the shared interface
def render(self, indent=0):
lines = [f"{' ' * indent}{self.name}/ ({self.size()})"]
lines += [c.render(indent + 1) for c in self.children]
return "\n".join(lines)
root = Folder("project",
File("README.md", 120),
Folder("src", File("app.py", 900), File("util.py", 300)),
Folder("assets", Folder("img", File("logo.png", 4000))),
)
print(root.render())
print("total:", root.size())
print("just src:", root.children[1].size())output
project/ (5320)
README.md (120)
src/ (1200)
app.py (900)
util.py (300)
assets/ (4000)
img/ (4000)
logo.png (4000)
total: 5320
just src: 1200Run and edit it in the app.
The client called size() once. It never checked whether something was a file or a folder, and render() works at any depth.
Watch it
How to implement it
- Make sure the domain really is a tree (part–whole).
- Define the component interface with operations meaningful for both leaves and groups.
- Implement leaves directly; implement composites by iterating children and combining results.
- Decide where child-management methods (
add,remove) live — only on the composite (safer) or on the interface (more uniform, but leaves must refuse them).
What does Composite let client code avoid?
When to use it — and when not to
Use it for part–whole hierarchies: file systems, UI widget trees, org charts, menus with submenus, expression trees, bills of materials. Skip it for flat collections, or when leaves and groups need such different operations that a shared interface would be mostly stubs.
Pros and cons
| Pros | Cons |
|---|---|
| Uniform treatment of one and many | A too-general interface can let you "add a child to a file" |
| New node types slot in (Open/Closed) | Hard to restrict which children a composite may hold |
| Recursive operations are natural | Deep trees can be slow if results aren't cached |
How it relates
- Iterator walks composite trees; Visitor runs new operations over them without adding methods to every node.
- Decorator has a similar shape (wrapping one child) but adds behaviour rather than aggregating.
- Builder is handy for constructing complex composite trees.
- Interpreter is a composite of grammar nodes.
- Chain of Responsibility often passes a request up a composite's parent links.
Which of these is the best fit for Composite?
Key terms
- Composite — A pattern where groups and single items share one interface, forming a tree.
- Leaf — A node with no children that performs the operation directly.
- Component — The shared interface of leaves and composites.
- Part–whole hierarchy — A structure where wholes are made of parts that may themselves be wholes.