library
intermediateComposition 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 you5
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.