Design the three Composite roles in Java deliberately so the shared contract stays useful and child-management rules stay explicit.
Composite uses three conceptual roles:
Component: the shared client-facing contractLeaf: a node with no childrenComposite: a node that owns childrenThe interesting design decision is what belongs on the Component contract.
Put operations on the component only when all nodes can support them meaningfully. If child-management methods such as add, remove, or children do not make sense for leaves, do not force them onto the shared interface just to satisfy a textbook diagram.
In Java, a narrow component interface often works better than a “transparent” composite interface that makes leaves throw UnsupportedOperationException.
A leaf usually owns:
If leaves start accumulating child-like behavior, the model may not actually need two roles.
The composite class owns:
That is where most bugs live.
Design the component API for client needs, not for diagram symmetry.