Dataslope logoDataslope

Aggregation and Dependency

The weaker "has-a" and "uses-a" relationships — borrowed parts and temporary collaborators

Not every relationship between two objects is the strong ownership we saw with composition. Often one object simply uses another, or holds a reference to another that exists independently. UML and the OOP tradition give these weaker relationships names: aggregation and dependency.

Knowing the difference is not pedantry — it changes how you draw your model, which object's constructor takes which, and what happens when one object goes away.

A spectrum of relationships

RelationshipLifetimeUML arrowJava shape
DependencyThe collaborator is borrowed for one method calldashed arrow ..>Method parameter or local
AggregationThe whole holds a reference, but the part lives independentlyopen diamond o--Field, but constructed outside and passed in
CompositionThe whole owns the part; both live and die togetherfilled diamond *--Field, usually constructed inside the whole

Aggregation: a Library has Members (who exist on their own)

A Library keeps a list of its Members. But each Member is a person who exists in the world whether or not the library does. If the library closed tomorrow, the members would not vanish — they would just stop being members. That is aggregation.

Code Block
Java 8 (Update 492)

Two signals in the code reveal that this is aggregation rather than composition:

  1. Library did not call new Member(...). It received the members from the outside.
  2. The same Member object could be registered with two different libraries simultaneously — the membership relationship is not exclusive.

Composition vs. aggregation, side by side

To make the difference vivid, here are two models of a House. In one, the Rooms are part of the house (composition). In the other, the Tenants are people who happen to live in the house this year (aggregation).

You can usually decide which one applies by asking: "If the whole disappears, does the part disappear too?" If yes → composition. If the part keeps existing → aggregation.

Dependency: a method that uses another object briefly

A dependency is the briefest relationship of all. One class doesn't hold a reference to another, but does briefly touch it to do its job. In the code, this usually looks like a method parameter or a local variable.

Code Block
Java 8 (Update 492)

OrderPrinter has no fields. It needs an Order and a Printer only for the duration of print. That is a dependency. It's the loosest possible coupling: as soon as print returns, the two references go away.

Why these distinctions matter in practice

The category you choose changes who is responsible for what:

QuestionCompositionAggregationDependency
Who creates the part?The wholeSomeone elseSomeone else (per call)
Where is the reference held?A field in the wholeA field in the wholeA parameter / local
What if the part is shared?It shouldn't beFineFine
Lifetime of the part?Tied to the wholeIndependentIndependent
Mental model"made of""knows about""uses for a moment"

In a real design, the same class often participates in all three kinds of relationships with different collaborators. A Library is composed of its Catalog, aggregates Members, and may depend on a Clock passed in just to stamp due dates.

Passing dependencies in: a tiny taste of injection

The healthy pattern is to pass collaborators in (via constructor or method parameter) rather than to construct them inside. This is sometimes called dependency injection when done systematically, but the simple version is just good Java.

Code Block
Java 8 (Update 492)

Because the logger is handed in, the same Greeter can be wired up with a different logger (a file logger, a silent logger, a test-spy logger) without changing a single line of Greeter's code. That is the deepest benefit of aggregation and dependency: they keep your classes loosely coupled and easy to recombine.

Practice

Challenge
Java 8 (Update 492)
Classroom aggregates Students

Implement two classes:

  • Student with a private final name and a name() accessor.
  • Classroom with:
  • a private final List<Student> students = new ArrayList<>();
  • enroll(Student s) adds the student.
  • size() returns the number enrolled.
  • names() returns the enrolled students' names joined by ", ". If the classroom is empty, return the empty string "".

The students are created in Main and handed inClassroom must not call new Student(...).

Expected output:

size=0
size=3
names=Ada, Bob, Cleo

Test your understanding

QuestionSelect one

A Library has a list of Member objects. Each Member exists as a person regardless of the library. Which relationship is this?

Composition

Aggregation

Dependency

Inheritance

QuestionSelect one

A method OrderPrinter.print(Order o, Printer p) takes its collaborators as parameters and doesn't hold them as fields. What kind of relationship is this?

Composition

Aggregation

Dependency (uses-a)

Inheritance

QuestionSelect one

Why is "passing collaborators in" (rather than constructing them inside the class) usually a better design?

It runs faster because there are fewer new calls

It saves typing

It keeps the class loosely coupled — the same class can work with different implementations or test stand-ins

It is required for the class to compile

On this page