Favor composition over inheritance
A car is a transport. A car has an engine. Reach for the second relationship the moment a second dimension of variation shows up.
Inheritance is the obvious way to reuse code, which is exactly why it gets overused.
Why it exists
The caveats only show up once you have hundreds of classes and no appetite for moving them:
- A subclass cannot shrink its parent's interface. Unused abstract methods still need bodies.
- Overrides must stay compatible with the base behavior, because client code holding a parent reference has no idea it got a child.
- Inheritance leaks the superclass's internals into the subclass, which is encapsulation quietly going out the back door.
- Subclasses are welded to superclasses. A change upstairs breaks things downstairs.
- Worst of all, inheritance extends in exactly one dimension. Model two or three independent dimensions with it and the class count multiplies instead of adding.
A class explosion, and its fix
Composition is the alternative. Inheritance is an "is a" relationship - a car is a transport. Composition is "has a" - a car has an engine. Instead of baking a behavior into the type, hold an object that provides it, and swap that object whenever you like, including at runtime.
Aggregation counts too, the looser variant where the container holds a reference without owning the lifecycle: a car has a driver, but the driver can walk away and take a bus.
If that shape looks familiar later, good: it is the Strategy pattern, arrived at from first principles rather than from a catalog. Most patterns are this move applied to a specific kind of pain.
Try it yourself: the transport model above still assumes cargo type (Car vs Truck) is the
one dimension worth a subclass. If a fourth dimension - say, ride comfort tier - showed up,
would you give Transport a fourth field, or has the class started doing too many jobs to
hold that many collaborators directly? Keep your answer in mind for the next page.
The cost of overapplying it
None of this makes inheritance a mistake. A single, shallow, genuinely "is a" hierarchy is
clearer than three interfaces and a constructor full of wiring, and composition is not free:
every extracted dimension is a constructor parameter, an interface, and a wiring decision
somebody has to make at startup. A Transport with one real cargo distinction (Car vs Truck)
and no other variation gains nothing from being decomposed into engine and navigation
interfaces it will never actually swap. Reach for composition when a second dimension of
variation shows up, not before.
How it relates to its neighbours
This principle answers one specific fork in the road: when a new variant shows up, do you extend a parent class or hold a reference instead? Composing Objects is the more general version of the same instinct, and it doesn't need an inheritance tree to be in the picture at all - it applies just as much to a single god object with no subclasses anywhere near it, which is exactly what its own page is about.
Where you'll see it in the pattern catalog
Strategy is this principle with a name, as the transport example shows directly. Decorator, Bridge, and State all lean on the same "hold a reference instead of extending a class" move, each solving a differently shaped version of the class-explosion problem above.
Check yourself
Why does "favor composition over inheritance" say favor rather than always?