WorkspaceLow-Level Design
← Course overview

Course navigation

On this page

Low-Level Design / Design Principles

foundation · 12 MIN READ

Composition over Inheritance

Composition assembles a behavior from collaborators that can vary independently. Favor it when an inheritance hierarchy would multiply subclasses for every combination of policies.

Reading completion is independent of quizzes and challenges.

What you’ll understand

  • Composition assembles a behavior from collaborators that can vary independently. Favor it when an inheritance hierarchy would multiply subclasses for every combination of policies.
  • Inject a shipping collaborator rather than introducing StandardCheckout and ExpressCheckout subclasses.
  • Evaluate the tradeoff: Composition introduces delegation and object wiring. Inheritance remains useful for genuine stable substitutable subtypes; the principle is a preference, not a universal ban.

Useful first: Classes and Objects

The idea and when to recognize it

Composition assembles a behavior from collaborators that can vary independently. Favor it when an inheritance hierarchy would multiply subclasses for every combination of policies.

  • Requirement: A checkout needs either standard or express shipping without becoming a different checkout subtype.
  • Change to anticipate: Change delivery policy while preserving the same checkout object contract.
  • Design goal: Inject a shipping collaborator rather than introducing StandardCheckout and ExpressCheckout subclasses.

Start with the concrete problem

A checkout needs either standard or express shipping without becoming a different checkout subtype.

Change delivery policy while preserving the same checkout object contract.

Direct implementationRevised design
Creating a subclass for every delivery option couples checkout identity to a changeable policy.Inject a shipping collaborator rather than introducing StandardCheckout and ExpressCheckout subclasses.
The baseline case can hide the problem. Compare the extension and boundary fixtures before accepting this design.Composition introduces delegation and object wiring. Inheritance remains useful for genuine stable substitutable subtypes; the principle is a preference, not a universal ban.

Responsibilities and contracts

Inject a shipping collaborator rather than introducing StandardCheckout and ExpressCheckout subclasses.

  • Checkout: Combines prices through a stable operation. Public operations: total(items)
  • ShippingPolicy: Hides fee selection. Public operations: fee()

Read the design

Select a participant to inspect its responsibility and public operations. Follow the labeled relationships; an arrow indicates direction, while the legend distinguishes ownership, substitution, and temporary use.

Preparing the design walkthrough…

Follow the interaction

Choose a supplied workload and compare the direct and revised implementations. Step through the same operation in both languages. Object values are recorded after each highlighted statement; previous steps remain unchanged.

Preparing the design walkthrough…

Implementation and expected output

Read the complete example alongside its input and expected output. The implementation selector changes the displayed program; the language selector preserves your current scenario and playback position.

Preparing the design walkthrough…

Try the idea in another setting

A game character can compose movement and attack behaviors instead of creating a subclass for every pair.

  • Name the new client contract before adapting the example.
  • Identify which state belongs to each object and who controls its lifetime.
  • Write one normal case and one boundary case before extending the design.

Tradeoffs and interview takeaways

Composition introduces delegation and object wiring. Inheritance remains useful for genuine stable substitutable subtypes; the principle is a preference, not a universal ban.

Common mistake: Creating a subclass for every delivery option couples checkout identity to a changeable policy.

  • Explain the choice: Inject a shipping collaborator rather than introducing StandardCheckout and ExpressCheckout subclasses.
  • Challenge your choice: Composition introduces delegation and object wiring. Inheritance remains useful for genuine stable substitutable subtypes; the principle is a preference, not a universal ban.
  • Describe a requirement that would make the simpler implementation sufficient.

Design challenge and knowledge check

Preparing the design walkthrough…

Make it your own

Saved on this device · 0/20,000

Reading completion is independent of quizzes and challenges.