Back to All Design Patterns
Pattern 16 of 22
Structural PatternINTERMEDIATE7 min deep dive
Composite Pattern Pattern
Composes objects into tree structures to represent part-whole hierarchies, letting clients treat individual objects and compositions uniformly.
Real-World Mental Model / Metaphor:
A computer file system. A Folder can contain Files AND other Folders. Calling `getSize()` on a Folder computes the total size recursively, treating leaf files and container folders uniformly.
Interactive Runtime Simulator
Test and tweak inputs dynamicallyInteractive Composite Pattern SimulatorLIVE PLAYGROUND
Interact with the controls below to see how this design pattern executes in memory at runtime.
Configure Chain Handlers (Toggle Failures):
CHAIN PIPELINE STATUS
Step 1: AuthHandler.check() -> PASSED
Step 2: RateLimitHandler.check() -> PASSED
Step 3: PayloadGuard.check() -> PASSED
The Problem It Solves
Having to write separate recursive loops and type checks (`if (item instanceof Folder) ... else ...`) to calculate totals across nested trees.
The Architectural Solution
Define a common Component interface with shared operations. Both Leaf (file) and Composite (folder) implement the interface.
Pattern Structure & Participants
| Participant | Role & Responsibility | Type |
|---|---|---|
| FileSystemComponent (Interface) | Common operation: getSize() | interface |
| File (Leaf) | Returns file byte size directly | class |
| Directory (Composite) | Contains children and sums their getSize() | class |
Collaboration Rules:
- Directory contains a List<FileSystemComponent>
- Client calls root.getSize() without caring about tree depth
Production Code Implementation
Composite Pattern.java
public interface FileSystemItem {
long getSize();
String getName();
}
public class FileItem implements FileSystemItem {
private final String name;
private final long sizeBytes;
public FileItem(String name, long sizeBytes) {
this.name = name;
this.sizeBytes = sizeBytes;
}
public long getSize() { return sizeBytes; }
public String getName() { return name; }
}
public class DirectoryItem implements FileSystemItem {
private final String name;
private final List<FileSystemItem> children = new ArrayList<>();
public DirectoryItem(String name) { this.name = name; }
public void add(FileSystemItem item) { children.add(item); }
public long getSize() {
return children.stream().mapToLong(FileSystemItem::getSize).sum();
}
public String getName() { return name; }
} When to Use:
- •When you have to implement a tree-like object structure.
- •When you want the client code to treat both simple and complex elements uniformly.
When to Avoid (Anti-Pattern):
- •When the tree elements share too few common operations, forcing awkward empty method implementations.
Staff Engineering Interview Insights & Gotchas
- Mention file systems, org charts, and DOM trees as the top 3 textbook examples of Composite.