Composite
Treat individual objects and groups of objects uniformly β client code works the same whether it's talking to a leaf or an entire tree.
Intent & Description
π― Intent
Model tree structures where both individual items and collections of items should be usable interchangeably.
π Context
You’re building a file system (files and folders), UI component tree (widgets and panels), or organization chart (employees and departments). Client code shouldn’t need to ask ‘is this a leaf or a container?’ before calling methods on it.
π‘ Solution
Define a Component interface with common operations (draw(), getSize(), render()). Leaf classes implement it directly. Composite classes implement it by delegating to their children and aggregating results. Client code calls the same methods regardless of depth in the tree.
Real-world Use Case
Source
π TL;DR
Leaves and containers share the same interface. Client calls draw() on a single shape or a group β same code. Great for recursive tree structures. Interface design can get awkward if objects are too different.
Advantages
- Client code uses one interface for the entire tree β no type-checking or special cases.
- Add new leaf or composite types without changing client code.
Disadvantages
- Forcing unrelated classes to share a common interface can make that interface overly generalized and awkward.
class Graphic {
draw() {}
}
class Dot extends Graphic {
constructor(x, y) { super(); this.x = x; this.y = y; }
draw() { console.log(`Drawing dot at ${this.x}, ${this.y}`); }
}
class CompoundGraphic extends Graphic {
constructor() { super(); this.children = []; }
add(child) { this.children.push(child); }
draw() {
this.children.forEach(child => child.draw());
}
}