creational
Composite
Compose objects into tree structures to represent part-whole hierarchies. Treat individual and composite objects uniformly.
Think about a file system. A file has a size. A folder has a size too, which is the total of everything inside it.
If files and folders are different types, every piece of code has to check which one it is holding. That check spreads everywhere and is easy to forget.
Composite gives both the same interface. Code calls getSize() and does not care whether it is talking to one file or a folder containing thousands.
An army — a soldier is a leaf; a squad contains soldiers; a platoon contains squads. Orders cascade down.
Key Concepts
1
One interface defines the operations, such as getSize() or render().
getSize()render()
2
A leaf implements it directly. A file just returns its own size.
3
A composite holds children and implements the same operation by asking each child and combining the answers. A folder adds up the sizes of everything inside it.
4
The recursion happens naturally, because a child may itself be another composite. Client code stays simple: it calls one method on the top and the structure handles the rest.
When to use it
- File system (files and directories)
- UI component trees
- Menu systems (items and submenus)
Watch out for
- Leaf nodes are forced to implement operations that make no sense for them (add/remove children), so you either throw at runtime or weaken the interface
- Type safety suffers: the client cannot tell a leaf from a composite without instanceof, which is the check the pattern claimed to remove
- Deep or cyclic trees make recursive operations expensive or non-terminating — depth limits and cycle detection are your responsibility
java
public interface Component {
double getPrice();
}
public class Product implements Component {
private final double price;
public Product(double p) { this.price = p; }
public double getPrice() { return price; }
}
public class Box implements Component {
private final List<Component> children = new ArrayList<>();
public void add(Component c) { children.add(c); }
public double getPrice() {
return children.stream().mapToDouble(Component::getPrice).sum();
}
}