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.
What the interviewer is probing.
1. "What does Composite let you do?" *Probing:* the purpose. *Stalls:* "Nesting." *Moves up:* treat individual objects and compositions uniformly, so client code does not branch on whether a node is a leaf.
2. "What is the design tension in it?" *Probing:* the depth. *Stalls:* "None." *Moves up:* whether child-management methods live on the common interface — uniform but leaves must reject them, or safe but clients must type-check.
3. "Give a real example." *Probing:* the recognition. *Stalls:* "I cannot." *Moves up:* a filesystem tree, a UI component hierarchy, or nested organisational structures where totals roll up.
4. "What is the traversal risk?" *Probing:* the practical angle. *Stalls:* "None." *Moves up:* cycles if the structure is not genuinely a tree, and deep recursion on large structures.
An army — a soldier is a leaf; a squad contains soldiers; a platoon contains squads. Orders cascade down.
Key Concepts
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();
}
}