Interview frequency: …
Short answer
Inheritance creates tight, fixed compile-time coupling and leads to the fragile base class problem, while composition allows behavior to be swapped dynamically at runtime with greater flexibility.
Explanation
Inheritance represents an "is-a" relationship that exposes parent-class details to the child (white-box reuse), and changing the parent can unintentionally break children (the Fragile Base Class Problem). Composition represents a "has-a" relationship (black-box reuse): an object holds references to other objects implementing specific interfaces, making testing and component replacement easier.
Code example
// Instead of rigid inheritance: class FlyingSwimmingDuck extends Duck
class Duck {
constructor(private flyBehavior: FlyBehavior, private swimBehavior: SwimBehavior) {}
performFly() { this.flyBehavior.fly(); }
}Common mistakes
- Using inheritance just to reuse a few lines of code when there is no real relationship between the types.