Implement Composite in Java with a clear component contract, disciplined child ownership, and traversal rules that fit recursive structures.
Composite: A pattern that lets clients treat individual objects and groups of objects through one shared contract.
Composite fits Java well when the data is genuinely tree-shaped and the client wants to apply the same operation to both leaves and containers.
1public interface PriceNode {
2 Money total();
3}
Leaves implement the operation directly:
1public record LineItem(String sku, Money price) implements PriceNode {
2 @Override
3 public Money total() {
4 return price;
5 }
6}
Composites hold children and delegate recursively:
1public final class Bundle implements PriceNode {
2 private final List<PriceNode> children = new ArrayList<>();
3
4 public void add(PriceNode node) {
5 children.add(node);
6 }
7
8 @Override
9 public Money total() {
10 return children.stream()
11 .map(PriceNode::total)
12 .reduce(Money.zero(), Money::add);
13 }
14}
The caller can depend on PriceNode and ignore whether it received:
That keeps client code smaller and lets recursive behavior live with the structure itself.
Composite is not just about “put objects in a list.” The hard questions are:
Those questions matter more than the inheritance diagram.
Composite is strong when the tree is real and stable enough to deserve first-class modeling.