LLD Hub
Learn

Composition over InheritancePrefer 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

CompositionTypeScript
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 →