Advanced OOP
Composition vs Inheritance
Choosing the right approach for code reuse
Interview: Design decisions — tests understanding of coupling, flexibility, and when to prefer composition over inheritance
"Prefer composition over inheritance" is one of the most important design principles in OOP. Composition means building objects from other objects ("has-a" relationship), while inheritance means extending a parent class ("is-a" relationship). Composition provides more flexibility and less coupling, making code easier to change and test.
When to Use Each
- Inheritance (is-a): Dog IS-A Animal, Square IS-A Shape
- Composition (has-a): Car HAS-A Engine, User HAS-A Profile
- Aggregation: Weak "has-a" — parts can exist independently
- When in doubt, prefer composition — it's more flexible
Why Composition Wins
- Flexibility: Swap components at runtime
- Testability: Mock individual components easily
- Loose coupling: Changes to one component don't break others
- No fragile base class: Avoid inheritance hierarchy issues
Common Pitfall
Deep inheritance hierarchies (>2-3 levels) are a code smell. If you're inheriting to reuse code (not to model "is-a"), switch to composition.
Use Cases
Building complex objects from interchangeable components
Strategy pattern: swappable algorithms (payment, sorting, compression)
Service layer: composing services from pluggable components
Game entities: composing behavior from independent component systems
Testing: replacing real components with mocks/stubs
Common Mistakes
Using inheritance for code reuse when composition would be more flexible
Deep inheritance hierarchies (>2-3 levels) that are hard to understand
Not injecting dependencies (hardcoding component creation inside classes)
Over-composing: sometimes simple inheritance is the right choice
Forgetting to define clear interfaces (protocols) between composed components