Composition, Inheritance & Delegation
intermediate14 min readLesson 69 of 180
Why addAll bypasses your override, and how composition with delegation sidesteps fragile base classes.
Composition, inheritance, and delegation
Inheritance is the strongest coupling Java offers: the subclass depends on superclass internals and survives every superclass change. Prefer composition: hold a collaborator and delegate.
// inheritance-flavored
class CountingList extends ArrayList<String> {
int count = 0;
@Override public boolean add(String s) { count++; return super.add(s); }
// broken: addAll() bypasses add(), remove() desyncs count...
}
// composition-flavored
final class CountingList {
private final List<String> inner = new ArrayList<>();
int count = 0;
void add(String s) { count++; inner.add(s); }
int size() { return inner.size(); }
}
The inheritance version inherits behavior it never asked for (addAll skips the override โ a classic bug). The composition version exposes exactly the surface it wants, and counting cannot desync.
Rule of thumb: is-a that survives every future change โ inheritance.
has-a, wrapping, decorating, adapting โ composition. When in doubt,
compose and delegate.