Module 8: Object-Oriented Design in Practice
Choose Composition Before Inheritance
See why small collaborator objects often produce cleaner code than deep inheritance trees.
Author
Java Learner Editorial Team
Reviewer
Technical review by Java Learner
Last reviewed
2026-04-17
Java version
Java 25 LTS
Learning goals
- Recognize when composition produces cleaner code
- Spot brittle inheritance hierarchies early
- Refactor behavior into reusable collaborators
Inheritance says “is-a”; composition says “has-a”: A Truck is a Vehicle, but a CheckoutService has a PaymentProcessor. That distinction matters.
Composition keeps behavior swappable: If a class contains another object, you can replace that collaborator later without rewriting the whole hierarchy.
Inheritance is strongest when the subtype really extends the same concept: If subclasses mostly override everything, the parent class was probably not the right base.
Practical mindset: Prefer composition by default. Use inheritance when the shared abstraction is stable and the child types genuinely belong under it.
Runnable examples
Composition keeps responsibilities separated
class EmailSender {
public void send(String message) {
System.out.println("Email: " + message);
}
}
class NotificationService {
private final EmailSender emailSender = new EmailSender();
public void notifyUser(String message) {
emailSender.send(message);
}
}Expected output
NotificationService has an EmailSender instead of becoming one.
Common mistakes
Creating subclasses for every small behavior variation
Extract a collaborator or strategy object instead of growing a subclass tree.
Calling protected parent internals all over child classes
That usually signals a hierarchy that is too tightly coupled.
Mini exercise
Refactor a `SmartTV extends Television` idea into a `Television` class that has a separate `StreamingApp` collaborator.
Summary
- Composition is often easier to test, replace, and evolve.
- Inheritance should model a true subtype relationship.
- If a subclass fights the parent, stop subclassing.
Next step
Now tighten your understanding of overriding rules so polymorphism stays predictable.
Sources used