All topics
library
intermediate

Composition over Inheritance

Know why delegation through composition is usually better than extending a class.

Composition means holding another object and delegating to it, instead of extending a class.

Inheritance = born into a family (can't choose parents). Composition = hiring specialists (choose and swap anytime).

Key Concepts

1
    // inheritance
    class Stack<E> extends ArrayList<E> { }      // also exposes add(int, E)
2
    // composition
    class Stack<E> {
      private final List<E> items = new ArrayList<>();
      void push(E e) { items.add(e); }
      E pop() { return items.remove(items.size() - 1); }
    }
3
The inheritance version exposes the wrong API. Extending ArrayList means callers can call add(0, e) and insert at the bottom of the stack. The composed version exposes only push and pop.
ArrayListadd(0, e)pushpop
4
Why composition usually wins.
    swap the delegate at runtime     inheritance is fixed at compile time
    mock the delegate in a test
    compose several behaviours       you may extend only one class
    the parent cannot break you
5
The fragile base class problem is the one that bites hardest. A subclass depends on how the parent is implemented, not just what it promises:
6
    class Counting<E> extends ArrayList<E> {
      int added;
      public boolean add(E e)             { added++; return super.add(e); }
      public boolean addAll(Collection<? extends E> c) {
        added += c.size(); return super.addAll(c);
      }
    }
7
addAll is counted twice, because ArrayList.addAll calls add internally. Nothing in the documentation said it would, and a later JDK release could change it either way.
addAllArrayList.addAlladd
8
The JDK's own example. Properties extends Hashtable, so put(Object, Object) is public on it — and that breaks the String-only contract Properties is supposed to keep.
Properties extends Hashtableput(Object, Object)Properties
9
When inheritance is right. The relationship really is "is-a", and the parent was designed and documented for extension. The Template Method pattern, where a parent defines the steps and subclasses fill them in, is legitimate inheritance.
10
What the interviewer is probing.1. "Why is 'favour composition over inheritance' the usual advice?" Probing: whether you can give a concrete failure, not a slogan. Stalls: "Inheritance is bad." Moves up: a subclass depends on the parent's implementation, so a parent change breaks it; composition depends only on a published interface.
11
2. "Give an example where inheritance broke something in the JDK." Probing: whether you know the standard example. Stalls: "I cannot think of one." Moves up: Properties extends Hashtable, so put(Object, Object) is public on it and bypasses the String-only contract Properties is supposed to keep.
12
3. "You extend ArrayList to count additions. Why is the count wrong?" Probing: self-use in the parent. Stalls: "It should be right." Moves up: addAll calls add internally, so each element is counted twice — and nothing in the documentation promised it would not.
13
4. "When is inheritance the right choice?" Probing: whether you apply the rule or recite it. Stalls: "Almost never." Moves up: a genuine is-a relationship with a class designed and documented for extension — the Template Method pattern being the clearest case.