Week 2: composition, built from "how does one object hold another?"
By the end you can give a class a field that is itself another object, read across the objects a class owns to
answer a question about the whole, and tell the three kinds of has-a apart so you know which objects a class
owns and which it only borrows. It builds straight on the Week 1 Course and on the Week 0 idea that an object
variable holds a reference.
The user story behind this. A department chair wants to load this term's courses into one Schedule object
and ask it a question about the whole, total credits, so that they can see the shape of the term before
committing to it. The chair does not want to add the numbers by hand every time a course changes. So the
Schedule has to hold the actual courses and read across them on request, which is the move this lesson
builds.
Before you start
You should be able to tick each of these. If one is shaky, do the matching review first, then come back.
- [ ] I can write a class with private fields and a constructor that validates them.
- [ ] I can explain that an object variable holds a reference, an arrow to an object built elsewhere.
- [ ] I can loop over a list with an enhanced-for and call a method on each element.
The problem (sit with this before reading on)
The chair needs a Schedule that can report its total credits. The tempting first move is to have the
Schedule store the number:
public class Schedule {
private int totalCredits; // updated by hand whenever a course is added
}
It works until the registrar corrects a course from four credits to five. The Course is fixed, but the
Schedule still reports the old total, because it copied the number instead of holding the course. The
Schedule and the catalog have drifted apart, and nothing in the code looks wrong.
Check yourself. In one sentence, why does storing totalCredits as its own number leave the Schedule
wrong after a course changes?
Atom 1: a field can be another object
A field does not have to be an int or a String. It can be any type, including a class you wrote and a
collection of them. The Schedule should hold the courses themselves, as a field whose type is a list of
Course:
public class Schedule {
private final List<Course> courses;
}
Now the Schedule does not store a stale total. It holds the actual Course objects, the same objects the
catalog has, and can compute anything it needs from them on demand. A class whose state is built out of other
objects is using composition: it is composed of its parts.
Check yourself. The field is private final List<Course> courses. In one sentence, what does the
Schedule hold now, an answer or the data the answer comes from?
Atom 2: reading across what you own
Because the Schedule holds the courses, the total-credits question becomes a loop that reads across them. The
Schedule answers for the whole by asking each part:
public int totalCredits() {
int sum = 0;
for (Course c : courses) {
sum = sum + c.credits();
}
return sum;
}
This is the heart of composition: the object that owns the parts is the right place to answer questions about the whole, because it is the one thing that can see all of them. The total is always current, because it is computed from the live courses every time it is asked.
Check yourself. A course is corrected from four credits to five in the catalog the Schedule shares. After
the fix, what does schedule.totalCredits() return, the old total or the new one, and why?
Atom 3: the three flavors of has-a, owns versus borrows
Saying a class has-a something is not precise enough, because there are three kinds, and they differ on one question: does this object own the other, or only borrow it. The difference decides who is responsible for the borrowed object's life, and in the next lesson it decides who has to make a copy.
- Composition: the object owns the part, and the part does not outlive it. A
Scheduleowns its list of sections; the list exists for the schedule and with it. - Aggregation: the object holds a part that outlives it. A
DepartmentholdsCourseobjects that stay in the catalog whether or not this department lists them this term. - Association: the object borrows a long-lived object for a while. A
Sectionborrows anInstructor, a person who exists independently and is shared across many sections.
You do not need to label every relationship perfectly today. You need the one distinction that matters next: an object you own is yours to protect, and an object you only borrow is shared, so a change through your reference is a change everyone sees.
Check yourself. A Section holds a reference to an Instructor who teaches three sections. Is that
composition or a looser has-a, and what does it mean if one section changes the instructor's data?
Where this is going
Atom 3 just reopened the Week 0 question with real stakes. The Schedule owns a List<Course>, but that
field is a reference, so if the Schedule ever hands that same list out to a caller, the caller can reach in
and reorder or drop courses, and the chair finds a change they never made. Owning a part is only half the job;
protecting it is the other half. That is the next lesson, defensive copy, and it is the payoff of the
value-versus-reference idea you built in Week 0.
Check yourself (competency close). Finish in your own words: "Composition means a class holds ___ as fields and answers questions about the whole by . The has-a I own, I must also , because the field is ___."
What you collected
- A field can be another object, even a list of objects; a class built from other objects uses composition.
- The owner of the parts is the right place to answer questions about the whole, by reading across them, so the answer is never stale.
- Has-a comes in three kinds: composition (owns), aggregation (holds something longer-lived), association (borrows a shared object). The one that matters now is owns versus borrows.
- An owned mutable field is still a reference, which is why the next lesson has to protect it.