Skip to main content
๐Ÿ“œ WAYPOINT LESSON

Composition, Inheritance & Delegation

โญโญ intermediateโณ 14 min read๐Ÿ“ Lesson 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.

โšก Now practice

Ready to Code
Design Lab: Payments & ShapesInject a fake gateway, dispatch sealed shapes exhaustively, and build a desync-proof delegating log.
3 challenges ยท ยท ~40 min