CodePark/ questions / OOP principles & composition
START PRACTICINGPRACTICE
Backend question · Software design & patterns › OOP principles & composition

What does "favor composition over inheritance" mean? Show how you would restructure this hierarchy.

class Notifier { send(msg: string) { /* email */ } }
class SmsNotifier extends Notifier { /* overrides send */ }
class LoggedSmsNotifier extends SmsNotifier { /* adds logging */ }
class RetryingLoggedSmsNotifier extends LoggedSmsNotifier { /* adds retry */ }
// Now we need logging + retry for email too...

It means: build behaviour by combining small objects, instead of by extending classes. The phrase comes from the Gang of Four book (Design Patterns).

Why inheritance causes problems:

  • It is fixed at compile time. You cannot change it while the program runs.
  • It is a white-box relationship: the child depends on the parent's internal code.
  • Each new combination of features needs a new subclass.

The hierarchy above explodes as soon as every channel needs logging and retry.

With composition, an object gets behaviour by holding other objects behind interfaces. Steps:

  • Define interface Notifier { send(msg: string): Promise<void> }.
  • Implement EmailNotifier and SmsNotifier.
  • Write LoggingNotifier and RetryingNotifier. Each one wraps any Notifier.

Now new RetryingNotifier(new LoggingNotifier(new SmsNotifier())) builds any combination at runtime. Each class has one job, and you can test each class alone.

Inheritance is still fine for a true, stable is-a relationship, where the child keeps the parent's contract (its promised behaviour).

  • Inheritance couples the child to the parent's code, and you need a new subclass for every combination.
  • Composition builds behaviour from small objects behind an interface.
  • You can combine wrappers at runtime in any order.
  • Inheritance is still fine for real, stable is-a relationships.