Composition
The "has-a" relationship — building rich objects out of smaller ones, and why composition is the most important relationship in OOP
A complete object model is never one giant class. It is a graph of small classes that hold references to each other. The most common — and most important — relationship between two classes is composition: one class is made out of another.
A
Carhas anEngine. AHousehasRooms. APersonhas anAddress. ALibraryhasBooks.
Every one of those sentences is a composition relationship in disguise.
The "has-a" relationship
Two classes can relate in many ways. The four we'll meet in this course are:
This page is about the strongest of them: composition. In a composition relationship, the whole owns the part. The part's lifetime is tied to the whole's. If the car goes to the junkyard, so does the engine.
In Java, composition looks like one class holding a private final
field of another type, with the part being constructed by the whole
(or handed in via the constructor) and never shared with anyone else.
A first example: Car has an Engine
The solid diamond *-- in UML means composition — strong
ownership. The Engine is part of the Car.
Things to notice:
- The
Engineis created inside theCar. No outside code ever gets a reference to it. - The
Car'sstart,stop, andrunningmethods delegate to the engine. The car does not implement engine logic itself — it asks the engine. - When the
Carbecomes unreachable, theEnginebecomes unreachable too. They live and die together.
Why composition matters
Composition is what lets you build big objects out of small ones. Each small one is well-encapsulated, easy to reason about, and easy to test. The big one just orchestrates.
If Library tried to do everything itself, it would be a 2000-line
class. With composition, each concept gets its own small class with
a focused job, and Library is mostly a coordinator.
Delegation: the partner of composition
A class that owns a part very often delegates part of its behavior to that part. Delegation just means "I'll ask the part to do this for me." It is the everyday verb of composition.
Person.city() doesn't keep a city field. It asks its Address.
If the rules for "what is your city" ever change, they change in one
place — inside Address.
Composition is the answer to most modeling problems
Beginners often reach for inheritance ("a SportsCar extends Car")
when composition would serve better ("a Car has an Engine, which
might be a sports engine"). We will study inheritance later, and you
will see how often the right move is to reach for composition first.
"Favor object composition over class inheritance" — Gang of Four
We're going to repeat that sentence several times this course. It is worth the repetition.
A richer example: a Computer composed of parts
This example shows multiple components combined into a whole, with each component encapsulated.
Computer has zero logic of its own about CPUs, RAM, or SSDs. It
delegates everything to the components and just assembles the
answer. That is the goal: a containing class that orchestrates, with
the real behavior living in well-defined parts.
Practice
Build a tiny model with two classes, Author and Book. A Book owns its Author.
Authorhas private final fieldsfirstNameandlastNameand a methodfullName()returningfirstName + " " + lastName.Bookhas private final fieldstitle(String) andauthor(Author), and a methodcitation()returningtitle + " by " + author.fullName()— that is,Bookdelegates toAuthor.
The provided Main will print:
Pride and Prejudice by Jane Austen
Test your understanding
Which of these is the clearest example of composition?
A Dog is a Mammal
A PrintService uses a Logger it was handed temporarily
A House has Rooms that are created and destroyed with the house
A Library keeps references to Books borrowed from a national archive
When Car exposes start() and internally calls engine.ignite(), what is that pattern called?
Inheritance
Polymorphism
Delegation — the Car asks its part (the engine) to do the work
Abstraction leak
Why is composition often preferred over inheritance when both are possible?
Composition is required by the Java compiler
Inheritance was deprecated in Java 17
Composition assembles small, swappable pieces, while inheritance locks classes into a rigid tree that's hard to change later
Composition methods always run faster