Composition over Inheritance — Prefer HAS-A over IS-A
Prefer HAS-A (inject a service) over IS-A when behaviour varies. · Deep trees are hard to change; composition stays modular.
Watch
Watch, then scroll down for code and practice.
In code
class EmailService {
send(to: string, body: string) { /* … */ }
}
class OrderService {
constructor(private mail: EmailService) {}
placeOrder() {
// …
this.mail.send("user@x.com", "Confirmed");
}
}📘 Key ideas
The problem with deep inheritance
Deep hierarchies (A extends B extends C) become rigid. A change to the base class ripples everywhere, and the Banana-Gorilla-Jungle problem kicks in.
Composition
Instead of extending a class to reuse behaviour, inject the dependency. Employee HAS-A PayrollService — it doesn't need to BE one.
When inheritance is OK
One level is usually fine when there's a genuine IS-A relationship. But if you're using inheritance just to reuse code, reach for composition instead.
Interfaces + composition
Define capability via interfaces (Payable, Manageable) and inject implementations. This makes roles mix-and-matchable without class explosions.
🧠 Practice — Apply What You Learned
🚀 Now apply what you learned
Pick a problem above, write your solution, and get AI feedback on your design.
Start Practice →