What if you could build software like LEGO blocks instead of fragile family trees?
Why Composition over inheritance in LLD? - Purpose & Use Cases
Imagine building a software system where every new feature means creating a new class that inherits from a big family tree of classes. You try to add a small change, but it forces you to rewrite or break other parts. It feels like juggling fragile glass pieces that can shatter with one wrong move.
Using inheritance heavily makes the system rigid and tangled. Changes in a parent class ripple unexpectedly to all child classes, causing bugs and confusion. It slows down development because you must understand the entire hierarchy before making even small updates.
Composition lets you build complex objects by combining simple, reusable parts. Instead of inheriting everything, you assemble behaviors and features as needed. This approach keeps code flexible, easier to understand, and safer to change without breaking unrelated parts.
class Bird extends Animal { fly() { /* fly logic */ } } class Penguin extends Bird { fly() { throw new Error('Cannot fly'); } }
class Bird { constructor(flyBehavior) { this.flyBehavior = flyBehavior; } fly() { this.flyBehavior.fly(); } } const canFly = { fly: () => console.log('Flying') }; const cannotFly = { fly: () => console.log('Cannot fly') }; const penguin = new Bird(cannotFly);
It enables building adaptable and maintainable systems by mixing and matching behaviors without deep class hierarchies.
Think of a smartphone: instead of one giant blueprint, it's made by combining parts like camera, GPS, and touchscreen modules. Each part can be upgraded or replaced independently, just like composing software features.
Inheritance creates tight, fragile class hierarchies.
Composition builds flexible objects by combining behaviors.
Composition makes code easier to change and maintain.