Composition over Inheritance — Notes
Why it usually wins
- Behaviours can be swapped at runtime.
- Easier to test (mock the collaborator).
- Avoids deep hierarchies (which are hard to reason about).
- Sidesteps multiple-inheritance issues.
When inheritance is fine
- Closed, stable hierarchies (Shape → Circle/Rect/Triangle).
- Templates and frameworks that explicitly require it (Spring's HandlerAdapter, Android Activity).
- Trivial extension where overriding is the natural mechanism.
"Favor composition" ≠ "never inherit"
- Single-level inheritance is often perfectly fine.
- Inheritance chains > 2 levels are a smell.
- "Marker interfaces" or sealed hierarchies model algebraic data types cleanly.
Refs
- Effective Java — Items 18 (favor composition over inheritance), 19 (design for inheritance or prohibit it).
- Design Patterns (GoF) — many patterns are composition-based alternatives to inheritance.
- Go: design and evolution talks — Go intentionally drops inheritance.