Code Safari

Chapter 97·Beginner·8 min read

Composition Over Inheritance: The Advice You'll Hear Most

A plain-English, language-agnostic guide to composition over inheritance — the difference between 'is-a' and 'has-a', why deep class trees turn brittle, and how building objects from parts keeps designs flexible.

July 15, 2026

You now know the four pillars: encapsulation, abstraction, inheritance, and polymorphism. The single most repeated piece of OOP design advice sits on top of them: favour composition over inheritance. This chapter explains what that means and why it's such common counsel.

Two ways to build a bigger object

There are two ways to give an object more capability:

  • Inheritance — an is-a relationship. A SavingsAccount is an Account and inherits its structure.
  • Composition — a has-a relationship. An Account has a TransactionLog and has an InterestPolicy, holding them as parts and delegating to them.
class Account:
    log    = new TransactionLog()      # has-a
    policy = new InterestPolicy()       # has-a
 
    method addInterest():
        deposit(policy.compute(balance))   # delegate to the part

Composition builds bigger objects by combining smaller ones and passing work to them, rather than climbing a class tree.

Why composition is usually preferred

Inheritance is rigid: the relationship is fixed at definition time, the subclass is tightly bound to the parent's internals, and deep trees become the fragile base class problem — a change up top ripples unpredictably down. Composition is looser:

Account has-a InterestPolicy
Swap in a different policy — at runtime, even
Account is unchanged; behaviour changes
Composition keeps the parts swappable
  • Swappable parts — give the account a different InterestPolicy and its behaviour changes, without touching the account or any class tree. You can even swap it at runtime.
  • Mix and match — combine capabilities freely instead of trying to express every combination as a subclass (the classic explosion where you end up wanting SavingsCheckingOverdraftAccount).
  • Looser coupling — a part is used through its interface, so it's far less entangled than a parent a subclass depends on.

The test, and the caveat

When you're unsure which to use, run the same test from the inheritance chapter:

  • Is B genuinely a kind of A? → inheritance may fit.
  • Does B merely need what A does? → give B an A as a part (composition).

Recap

  • Composition ("has-a") builds objects by combining and delegating to smaller parts; inheritance ("is-a") builds them by extending a parent.
  • Composition is usually preferred for flexibility: parts are swappable, capabilities mix and match, and coupling is looser.
  • Deep inheritance trees turn brittle; composition sidesteps the fragile-base-class trap and the subclass explosion.
  • It's a default, not a ban — inherit for genuine, stable "is-a" relationships; otherwise, compose.

That completes the concept-first tour of OOP: objects and classes, the four pillars, and the design instinct that ties them together. From here, the ideas transfer to any object-oriented language you pick up — the syntax changes, the concepts don't.

Composition Over Inheritance: The Advice You'll Hear Most | Code Safari