Inheritance vs Composition
| Feature | Inheritance | Composition |
|---|---|---|
| Goal | Reuse behavior via “is-a” relationship | Reuse behavior via “has-a” relationship |
| Coupling | Tight coupling | Loose coupling |
| Flexibility | Less flexible to change | More flexible and modular |
| Code Reuse | Inherits all parent behavior | Reuses specific behavior only when needed |
| Use When | Natural hierarchy exists | You want to compose behavior dynamically |
| Downsides | Fragile base class problem, tight coupling | May involve more boilerplate |
When to use Composition?
- You want to combine behaviors flexibly.
- You’re designing for loose coupling and testability.
- You want to avoid unintended inheritance side effects.
Inheritance vs Composition Minimal example
Inheritance
Composition
Example: Car and Engine
Inheritance (bad design): Using inheritance wrongly can produce inflexible code. In this example, Car inherits from Engine – implying “Car is an Engine,” which is semantically incorrect. This violates design clarity (a subclass shouldn’t introduce impossible behavior) and tightly couples Car to Engine.car.start() prints: