0/0
Design Patterns

Composite Pattern

A structural pattern that composes objects into tree structures to represent part-whole hierarchies, and lets clients treat individual objects and compositions of objects uniformly — one polymorphic call dissolves an entire forest of instanceof checks.

Explore Topics

🌳
Intent
Treat trees and leaves with the same polymorphic call
🌳 Composite Tree Lab — Drawing, Kitchen, and Financial trees side-by-side
Shape tree — Triangle/Circle leaves + nested Drawings. The operation draw(color) is pre-order recursion: print the composite header, then recurse into every child.
Visited 0 / 6
🌳 Tree structure (6 nodes)pre-order
▾▼Drawing "Outer"(3 children)composite
Ā·ā—Circleleaf
▾▼Drawing "Inner"(2 children)composite
Ā·ā–²Triangleleaf
Ā·ā—Circleleaf
Ā·ā–²Triangleleaf
šŸ“œ outer.draw(color) — call trace0 calls
Click ā–¶ Step to advance the recursion one node at a time, or ā­ to watch the entire draw() traversal animate.
The same polymorphic call outer.draw(color) works on every node in the tree — leaves are terminal, composites forward to their children. The Client never branches on type; the recursion is encoded inside the Composite class.
🌳
Intent
Treat trees and leaves with the same polymorphic call

Composite is a **structural** GoF pattern with one of the cleanest one-line intents in the catalog: "Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly." Read that twice. The first half is about **structure** (build a tree). The second half is about **uniformity** (the Client cannot tell — and does not care — whether the thing it is operating on is a single leaf or a 10,000-node forest). When `shape.draw("blue")` works identically on a `Triangle` and on a `Drawing` that contains 50 other Drawings, you have eliminated an entire class of `instanceof` checks from your client code.

Key Ideas
  • **Tree structure** — leaves at the bottom, composites in the middle, each composite holds Components which themselves may be leaves or composites. The recursion is intentional and is the whole point.
  • **Uniform treatment** — the Client calls `component.operation()` without knowing or caring whether the component is a Leaf or a Composite. Polymorphism does the dispatch.
  • **Recursion lives inside the Composite** — the Client never writes a recursive loop. The Composite forwards each operation to its children, and the children either recurse further (if they are Composites themselves) or terminate (if they are Leaves).
  • **One polymorphic call replaces N instanceof branches** — every new node type would otherwise add another branch to every traversal site in the client code. With Composite, new node types just implement the Component interface.
Strengths
  • ✦The Client becomes a one-liner. `drawing.draw("blue");` regardless of how deep the tree goes.
  • ✦Adding a new leaf or composite type is purely additive — the existing Client code does not change at all (Open/Closed Principle).
  • ✦Recursive operations (sum, render, search, serialize, count) become natural — the recursion is encoded once, in the Composite's implementation.
Weaknesses
  • ā–³Defining a Component interface that fits **every** leaf and **every** composite is the hard part — for some operations, "what should a Leaf return?" has no good answer.
  • ā–³It is easy to accidentally create a tree with cycles (composite A contains composite B contains composite A), and the recursive operations will then stack-overflow.
  • ā–³Operations that need to know "am I a leaf or a composite?" can pierce the abstraction and force `instanceof` checks back into the Client.
Used in:A drawing application where the user builds shapes (`Triangle`, `Circle`) and groups them into Drawings — which may themselves contain other Drawings as sub-groups. When the user clicks "Fill with blue", the application calls `drawing.draw("blue")` exactly **once**, on the top-level Drawing. The recursion painted across the entire tree happens automatically, because every node — leaf or composite — implements the same `Shape` interface with the same `draw(color)` method.
Code Snippets

Quiz

Intent Quiz
QUIZ 1/6
Which statement best captures the **intent** of the Composite pattern?

Diagrams

Composite Pattern — GoF structure (4 roles + self-containment)
Loading diagram...
Concrete example — Kitchen Staff hierarchy (Component / Leaf / Composite)
Loading diagram...

Practice

Drag each class, interface, or expression into the Composite role it fills. Two items are traps — they belong to a DIFFERENT GoF pattern and should be sorted into the trap bucket.
EXERCISE 1/5
interface Shape { void draw(String color); }
abstract class AccountComponent { abstract float getBalance(); }
class Triangle implements Shape { public void draw(String c) { ... } }
class DepositAccount extends AccountComponent { float getBalance() { return balance; } }
class Drawing implements Shape { List<Shape> children; public void draw(String c) { for (Shape s : children) s.draw(c); } }
class CompositeAccount extends AccountComponent { List<AccountComponent> kids; float getBalance() { float t=0; for (var c:kids) t+=c.getBalance(); return t; } }
main(): Shape s = new Drawing(); s.add(new Triangle()); s.draw("red");
class DiscountDecorator implements GroceryItem { GroceryItem wrapped; double price() { return wrapped.price() * 0.85; } }
class LoggerSingleton { private static LoggerSingleton INSTANCE; }
Component (the shared interface every node implements)
Leaf (terminal node with no children)
Composite (non-terminal — holds children of Component type)
Client (works through the Component interface only)
NOT Composite (belongs to a different pattern)
Predict the line-by-line output of `outer.draw("red")` for this 2-level nested Drawing tree
EXERCISE 2/5
Drawing inner = new Drawing("Inner"); inner.add(new Triangle()); inner.add(new Circle()); Drawing outer = new Drawing("Outer"); outer.add(new Circle()); // a leaf outer.add(inner); // a composite child outer.add(new Triangle()); // another leaf outer.draw("red"); // Drawing.draw() prints "[Name] expanding N child shape(s) in COLOR:" // Triangle/Circle.draw() prints " Drawing X with color COLOR"
Line 1
Line 2
Line 3
Line 4
Line 5
Line 6
Find the cycle — this Composite tree will crash with StackOverflowError
EXERCISE 3/5
Click on the line you think contains the bug, then press Confirm.
1CompositeAccount a = new CompositeAccount("a");
2CompositeAccount b = new CompositeAccount("b");
3
4a.add(new DepositAccount("DA-1", 100));
5b.add(new DepositAccount("DA-2", 200));
6
7a.add(b); // a now contains b
8b.add(a); // ⚠ b now contains a — CYCLE
9
10// The whole point of Composite — recursive operations —
11// becomes a JVM-killer:
12float total = a.getBalance(); // ← infinite recursion
13// Stack trace:
14// getBalance ← a
15// getBalance ← b
16// getBalance ← a
17// getBalance ← b
18// ... ~10,000 frames ...
19// StackOverflowError
Order the lines to write the canonical recursive Composite `getBalance()` — initialize total, iterate children, recurse, return
EXERCISE 4/5
Drag the lines into the correct order.
return total; // 4) aggregate done — return
public float getBalance() {
total += c.getBalance(); // 3) the RECURSION (polymorphic call)
float total = 0f; // 1) start at the identity (0 for sum)
}
for (AccountComponent c : children) { // 2) iterate every child
} // end of for loop
8 Composite-pattern myths — true or false?
EXERCISE 5/5
A Composite must implement the same interface (or extend the same base class) as its Leaves.
A Composite can contain another Composite of the same type — and that is the whole point.
The Client must use `instanceof` to check whether it has a Leaf or a Composite before calling operations.
Composite is a behavioral pattern.
In the Transparent variant, calling `add(child)` on a Leaf is a compile error.
A Composite's `operation()` always recurses on every child — the recursion is mandatory.
Composite and Decorator are the same pattern with different names.
A Composite tree can have cycles, and Java will detect them at compile time.

References

šŸ“š

Gamma, Helm, Johnson, Vlissides — Design Patterns: Elements of Reusable Object-Oriented Software (GoF, 1994) — Composite chapter

en.wikipedia.org

book
šŸ“„

Refactoring.guru — Composite Pattern

refactoring.guru

article
šŸ“š

Freeman, Robson, Bates, Sierra — Head First Design Patterns, 2nd Edition (Composite + Iterator chapter)

oreilly.com

book
šŸ“‹

Oracle Java Docs — java.awt.Container (Swing/AWT's canonical Composite — Container.add(Component))

docs.oracle.com

docs
šŸ“‹

Oracle Java Docs — java.io.File (the JDK's file-system Composite — listFiles() returns child Files)

docs.oracle.com

docs
šŸ“„

SourceMaking — Composite Design Pattern (with C++ and Java side-by-side examples)

sourcemaking.com

article