Skip to content

Composition builds behavior by connecting objects with smaller responsibilities. Inheritance builds behavior through a parent and subtype relationship.

Prefer composition when behavior must vary independently, when several behaviors must be combined, or when inheritance would create a deep class hierarchy.

Inheritance can be simple when the subtype relationship is stable and meaningful. It becomes costly when subclasses exist mainly to reuse implementation or select behavior.

Composition makes dependencies explicit. It also lets a caller replace one behavior without changing the identity of the object that uses it.

Composition can introduce more objects, interfaces, and wiring. This cost is not justified when the behavior is small, fixed, and unlikely to vary.

Inheritance can remain the clearer design when the domain has a real subtype relationship and the inherited contract is stable.

A deep inheritance hierarchy can couple unrelated concerns. A change to a base class can affect subclasses that were not part of the original change.

Composition can fail in a different way. Too many small abstractions can make a simple flow difficult to follow.

Use composition when:

  • behavior varies independently from the object that uses it;
  • several behaviors must be combined;
  • callers need to replace a dependency;
  • inheritance would exist mainly for code reuse.

Inheritance can be suitable when:

  • the subtype relationship is real and stable;
  • callers can safely use the subtype anywhere the parent is expected;
  • shared behavior belongs to the inherited contract;
  • the hierarchy stays shallow and understandable.

Prefer composition as a default design tool. Do not replace a simple and valid subtype relationship with extra abstractions only to avoid inheritance.

  • Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley, 1994.