โšกLLD Hub
Learn

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

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 โ†’