Free tools Windows power users keep installed
One-click scans. No signup required.
iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
Composition is often a better way to reuse or vary behavior because an object delegates work to collaborators instead of inheriting a fixed parent implementation. That can make behavior easier to replace and reduce dependence on implementation details—but it is a preference, not a ban on inheritance. Use inheritance when a type is genuinely substitutable for its parent or when a framework deliberately defines a subclass extension point.
What composition and inheritance mean
Inheritance derives a class from another class, allowing the derived class to use or override behavior from its parent. Composition builds an object from, or connects it to, other objects that do parts of its work. The usual shorthand is that inheritance models an “is-a” relationship, while composition models a “has-a” relationship. The shorthand helps, but behavior matters more than the label: a subclass should honor the behavior clients expect from its parent.
For example, an illustrative notification service could inherit from a particular email sender to reuse its delivery method. With composition, it could instead hold a reference to a sender collaborator and ask that collaborator to deliver a message. If the service needs to support different delivery methods, that collaborator can be replaced with another compatible implementation.
Why composition can be more flexible
It reduces dependence on a parent’s internals
A subclass is connected to its parent’s implementation as well as its public behavior. A change to the parent can require changes in child classes, limiting flexibility and reuse. The authors of Design Patterns: Elements of Reusable Object-Oriented Software describe the principle succinctly: “Favor object composition over class inheritance.”
#1 Best Overall
With composition, the containing object can depend on a collaborator’s interface rather than how that collaborator works internally. The collaborator can change—or be replaced—without requiring the containing class to adopt a new parent implementation. This shifts the dependency boundary; it does not eliminate coupling. The interface itself still needs to be well designed.
It lets behavior vary independently
When a capability or algorithm needs to vary independently of the object using it, a collaborator gives that behavior its own place and boundary. The containing object delegates the relevant work, rather than accumulating subclasses for every combination of behaviors. This can also help keep components focused: the Gang of Four authors write that “Favoring object composition over class inheritance helps you keep each class encapsulated and focused on one task.”
Rank #2
When inheritance is the better fit
Inheritance can be clear and appropriate when the derived type is a valid behavioral subtype: clients can use it wherever they expect the parent without encountering broken assumptions. It is also a natural choice when a framework explicitly expects developers to extend a base class through defined hooks. In these cases, the parent-child relationship is intentional, and the inherited contract—not merely the convenience of borrowing code—supports the design.
Recommended Free Tools
Do not assume that an “is-a” phrase alone proves substitutability. A child that changes or weakens behavior clients rely on may be a poor subtype even if its name sounds like a kind of parent. If the goal is only to reuse a few methods, a collaborator may be a better boundary.
Trade-offs to check before choosing
| Question | Composition | Inheritance |
|---|---|---|
| What relationship does it express? | An object collaborates with or contains another object (“has-a”). | A derived class extends a parent (“is-a”), if the behavioral contract holds. |
| Where does the dependency sit? | On collaborator interfaces and the delegation between objects. | On the parent class, including implementation details a child may rely on. |
| How easily can behavior change? | A compatible collaborator can be swapped, including at runtime when the design allows it. | Behavior is tied to the class hierarchy and its extension points. |
| What complexity can it add? | More objects and wiring; delegation can become hard to follow if spread across too many collaborators. | Unwanted inherited methods or parent changes that force child changes. |
| What else should be considered? | Separate components may duplicate some code. | Useful when a stable, intentional extension contract or sound subtype relationship exists. |
The NASA Software Engineering Handbook recommends composition for reuse, noting that inheritance creates a dependency between child and parent classes, while composition can offer more freedom and reduce inheritance hierarchies. These are qualitative design trade-offs, not a measured guarantee that composition reduces defects, maintenance time, or cost.
A practical decision checklist
- Check substitutability. Can the proposed child honor the parent’s behavior contract for the clients that use it? If not, do not inherit just to borrow implementation.
- Identify what needs to vary. If an algorithm, capability, or external service should be changeable independently, define a collaborator boundary and compose it.
- Check for a deliberate extension point. If a framework documents a subclass hook, inheritance may be the intended mechanism.
- Trace delegation. Make sure the collaboration and object wiring remain understandable; too many small collaborators can obscure how work flows.
- Compare the actual costs. Consider unwanted inherited behavior and parent-child coupling against extra objects, wiring, and possible code duplication.
Composition and inheritance can work together
The choice is not always either-or. The Gang of Four treat composition and inheritance as complementary: inheritance can create reusable components that are then composed into larger objects. Their warning is against overusing inheritance for reuse, not against inheritance itself. Choose the mechanism that makes the behavior contract and the points of change easiest to understand.
Sources: NASA Software Engineering Handbook, “Prefer Composition over Inheritance while Reusing the Functionality”; University of Cambridge course material, “Design Patterns: Inheritance vs composition”; Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley, 1994).
Quick Recap
Best Value
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

