Lesson 2 of 518 minModule progress 0%

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

How this lesson was prepared: AI-assisted draft, manually edited for clarity, and checked against current Java documentation and runnable examples.

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

Advertisement

Lesson check

What is the main advantage of composition here?

Next lesson →