devnotes.

Why 'Favor Composition Over Inheritance'?

This is one of the most repeated pieces of advice in OOP design, for concrete, well-understood reasons.

Problem 1: Inheritance is decided at compile time and is rigid. Once Sedan extends Car, that relationship is fixed for the life of the class — you can't swap it at runtime. Composition, by contrast, can be assembled and reassembled dynamically:

// Rigid — locked in at compile time
class ElectricCar extends Car { ... }

// Flexible — the engine can be swapped at runtime
class Car {
    function __construct(private engine) {}
    function replaceEngine(newEngine) { this.engine = newEngine }
}
car.replaceEngine(new ElectricEngine()) // impossible to do this cleanly with inheritance

Problem 2: Deep inheritance hierarchies become fragile. This is known as the fragile base class problem — a seemingly safe change to a base class several levels up can silently break behavior in distant subclasses that depend on details of the original implementation, often in ways that are hard to trace.

Problem 3: Inheritance exposes more than necessary. A subclass automatically inherits every public and protected member of its parent, even ones it doesn't need or that don't make sense for it — leading to broken or nonsensical behavior (the classic textbook example: Square extends Rectangle, where setWidth() and setHeight() inherited from Rectangle don't behave sensibly for a Square, since changing one must also change the other).

Composition avoids all three problems: dependencies can be swapped at runtime, a class only exposes the specific behavior it explicitly delegates to, and there's no hidden chain of inherited behavior to reason about — you only need to understand the object's own code plus the direct interfaces of the objects it composes. This is why modern OOP design, and many modern frameworks, increasingly favor composing small, focused objects together over building deep class hierarchies — reserving inheritance for cases with a genuinely stable, well-understood 'is-a' relationship.

Favor Composition Over Inheritance: Why It Matters | DevNotes