Today we will learn something very important, which is called relationships. I will make it simple for you. There are three relationships we will learn. There is a Dependency relationship, there is Aggregation, and there is Inheritance. Very simple!
Class A temporarily uses Class B (as a method parameter or local variable). B is not part of A's identity — just a tool.
📦
Aggregation
"has"
Class A has a Class B stored as a field. Comes in two strengths: Aggregation (weak) and Composition (strong).
🧬
Inheritance
"is"
Class A is a type of Class B. Studied in Module 06.
📌 Aggregation has two strengths
Both Aggregation and Composition are "has-a" relationships — they both mean one class stores another as a field. The difference is the lifetime of the contained object.
📦
Aggregation
"has-a" (weak)
The contained object can exist independently. It can be shared among multiple owners. Open diamond ◇ in UML.
💎
Composition
"owns-a" (strong)
The contained object cannot exist without its owner. It dies when the owner dies. Filled diamond ◆ in UML.
🎓 The Working Scenario — Four Classes
👨🏫
Professor
Imagine we have a Student class. The students suggested: "We should break the student down into smaller objects — the student has an Address and a Name, and both can be objects!"
👨🏫
Professor
So we now have a class Address — it has street name, city (e.g. "Jeddah"), and unit number (e.g. 100). We have a class Name — it has first name, middle name, last name. And we have a class BMICalculator — you pass in the weight in kilograms and height in centimetres, and you get the BMI. That is it!
So how many classes? Four classes: Student, Address, Name, BMICalculator. Now — what is the relationship among them?
Four classes — three different types of relationship with Student
2
Dependency — "uses"
To decide what kind of relationship BMICalculator has with Student, we do not start with the code — we start with the model. We ask one philosophical question: "Is the BMICalculator part of the student's identity?" The answer to that question determines everything.
🏫 Step 1 — The Identity Question: What defines a student?
👨🏫
Professor
Let me ask you this: what defines a student? What are the things that make this student who he is?
🙋
Students
His name, his ID number, his address, his marks!
👨🏫
Professor
Exactly. Name, ID, address, marks — these are the things that constitute the identity of the student. They describe who he is. Now — does the BMICalculator define him? Is it part of who he is?
🙋
Students
No… the BMICalculator is not who he is. It is just something he uses.
👨🏫
Professor
Correct! Now imagine the BMICalculator is a device — a machine standing in the corridor of the university. The student walks up to it, enters his weight and his height, gets his BMI value, and walks away. The machine is not part of him. He does not carry it. He does not own it. Any student can use it. It has nothing to do with his identity.
🧠 Step 2 — Philosophy First, Code Second
👨🏫
Professor
So the decision is made at the model level, not the code level. Because BMICalculator is not part of the student's identity, we do not store it as a data field inside the student. We use it only when we need it — we pass it as a method parameter. That is what you will see in the code. But the reason is philosophical — not syntactic.
🙋
Student
Professor — but what if I did write it as a data field? Would it then become aggregation?
👨🏫
Professor
Great question — and the answer depends on the real world. Ask yourself: does every student own a personal BMICalculator device? If every student carried their own personal machine — one that belongs to them and no one else — then yes, it would make sense to store it as a field, and the relationship would be aggregation. But look at what BMICalculator actually is. It holds no student data. It has no connection to any particular student. It is a shared tool — like the machine in the corridor that any student can walk up to and use. No student owns one. No student carries one as part of who they are. So if you write it as a field, the code will compile — but you have described something that is not true in the real world. The code is supposed to reflect the model. If the code contradicts the model, the code is wrong.
🙋
Students
So the rule is: if it is not part of identity → do not make it a field → use it as a parameter → and that is dependency!
👨🏫
Professor
Exactly! ✅ And notice — we can even go further and make getBMI() a static method. Because the BMICalculator has no connection to any specific student, we do not even need an object — we just call BMICalculator.getBMI(weight, height) directly. This is the most natural way to express that it is purely a utility tool, with no ownership and no identity relationship.
⚠️ Key Principle — Model decides the relationship, not the code
Question to ask
Answer
Relationship → Code consequence
Is it part of the student's identity?
YES (Name, Address)
Aggregation / Composition → store as a field
Is it part of the student's identity?
NO (BMICalculator)
Dependency → use as a method parameter (or make static)
Direction of reasoning: Philosophy → Model → Code. Never the other way around. If you happen to write BMICalculator as a field, that does not make it aggregation — it makes it a modeling error.
Dashed open arrow = Dependency ("uses" relationship)
📄 BMICalculator.java — used as a dependency
public classBMICalculator {
private double weight; // in kgprivate double height; // in meterspublicBMICalculator(double weight, double height) {
this.weight = weight;
this.height = height;
}
public doublegetBMI() {
return weight / (height * height);
}
}
// In Student class — dependency: BMICalculator is a method PARAMETER, not a fieldpublic doublecalculateBMI(BMICalculator calc) {
return calc.getBMI(); // used temporarily — NOT stored as a field!
}
// ── OR using static method (even cleaner — no object needed at all) ──public classBMICalculator {
public static doublegetBMI(double weight, double height) {
return weight / (height * height);
}
}
// In Student: no object created, just call the calculator directlydouble bmi = BMICalculator.getBMI(70, 1.75);
3
Aggregation & Composition — "has"
Both aggregation and composition are "has-a" relationships — the class stores another object as a data field. The key question is always: "Can the contained object survive without the owner?"
🏫 Step 1 — What does "Aggregation" mean?
👨🏫
Professor
One question — what does "aggregation" mean? We have two terms to understand: the aggregating class and the aggregated class.
Aggregation means aggregating — collecting things together. In our case, the Student class is the aggregating class — it collects other objects inside it. The Address and Name are the aggregated classes — they are collected inside the student.
🏠 Step 2 — The Apartment Analogy: Composition vs Aggregation
👨🏫
Professor
Let me ask you a very simple question. Can you imagine a Name without a Student? Can we say "this is Ali Fahad" — but where is he? He belongs to what? Who is this name for? There is no student — there is no name!
🙋
Student
That is true, Professor. "Ali Fahad" cannot exist by itself without belonging to someone. The name only makes sense if there is a person — a student!
👨🏫
Professor
Now imagine three students — Ali, Khalid, and Fahad — living in the same apartment on Al-Jami'a Street, Unit 100, Jeddah. They all share the same address.
Now Ali leaves the university. What happens to the address "Al-Jami'a Street, Unit 100, Jeddah"? Does it disappear?
🙋
Students
No! The address still exists — Khalid and Fahad still live there! The address survived even though Ali left.
👨🏫
Professor
Exactly! ✅ But if Ali died — then the name "Ali Fahad" must die with him. Can you see the relationship?
🔵 Address → Aggregation (weak): the address can be shared and still exists independently of any single student.
💚 Name → Composition (strong): the name cannot exist without its student — it dies with the student.
🙋
Students
Wow! 😮 And the BMICalculator — it is not part of the student at all, right? It is not aggregation either. It is just used temporarily — dependency!
👨🏫
Professor
Perfect! The BMI calculator is only a tool used temporarily to calculate a value — it does not contribute to the identity or definition of a student. That is precisely why it is dependency, not aggregation. 🎉
Aspect
🔵 Aggregation (weak)
💚 Composition (strong)
Keyword
"has-a"
"owns-a"
Lifetime of contained object
Survives independently — can be shared
Dies when the owner dies — exclusive
Real-world example
Student & Address (3 students, 1 address)
Student & Name (name dies with student)
UML symbol
Open diamond ◇
Filled diamond ◆
Java: where is the object created?
Created outside — passed in as a parameter
Created inside the constructor with new
PlantUML Class Diagram — Student ◆ Name (composition) | Student ◇ Address (aggregation) | Student - - → BMICalculator (dependency)
🏫 Step 3 — The Student's Challenge: How Do I Write This in Java?
👨🏫
Professor
My students — we have now studied aggregation and composition closely. You know the example: Student, Name, and Address. You know which one is composition and which one is aggregation. Good!
🙋
Student
Professor — I understand the concept. But I have a challenge. When I go to write the Java code… how do I actually make the Name object die when the Student is destroyed? And how do I make the Address stay alive? The UML shows a diamond ◆ or ◇ — but how do I express that in code?
👨🏫
Professor
Excellent question — this is exactly what you must understand to become a good programmer. The answer is one rule: it is all about where you write new.
For composition ◆ — you write new Name(...)inside the Student constructor. That Name object is created by the student, owned by the student, and has no other reference outside. When the student is gone — the name is gone with it. No one else holds a reference to it.
For aggregation ◇ — you create the Address object outside, in main or somewhere else, and then you pass it in to the constructor. Now multiple students can hold a reference to the same address object. When one student is destroyed, the address is still alive — because the other students still have their reference to it.
🙋
Students
Ahh! So the secret is where the new is written!
— new is inside the constructor → composition ◆ → dies with the owner
— new is outside, object passed in → aggregation ◇ → can survive independently
👨🏫
Professor
Exactly! ✅ That is the single rule you must practice. Look at the code carefully — the Student constructor receives first and last as plain String parameters, then calls new Name(first, last) right there inside. That is composition. But for address, it receives an Address object that was already created outside — that is aggregation. One constructor, two different relationships, expressed by one small difference in where new is written.
📄 Student.java — composition vs aggregation in code
public classStudent {
private int id;
privateName name; // ◆ COMPOSITION — will be created INSIDEprivateAddress address; // ◇ AGGREGATION — will be received from OUTSIDE// Name is created HERE inside the constructor → composition
// Address is passed in from outside → aggregationpublicStudent(int id, String first, String last, Address address) {
this.id = id;
this.name = newName(first, last); // ◆ composition: created insidethis.address = address; // ◇ aggregation: shared object from outside
}
publicStringgetFullName() { return name.getFullName(); }
publicAddressgetAddress() { return address; }
// Dependency: BMICalculator used temporarily as a method parameter — NOT storedpublic doublecalculateBMI(BMICalculator calc) {
return calc.getBMI();
}
}
// ── In main ────────────────────────────────────────────────────────────
// One address object — shared by multiple students (aggregation)Address sharedAddress = newAddress("Al-Jami'a St", "Jeddah", 100);
Student ali = newStudent(1, "Ali", "Fahad", sharedAddress);
Student khalid = newStudent(2, "Khalid", "Nasser", sharedAddress);
Student fahad = newStudent(3, "Fahad", "Salem", sharedAddress);
// All three share the SAME address object — if ali is gone, khalid & fahad still have it ✅
// Each student has their OWN name object — created inside their own constructor ◆
✅ The Key Programmer's Rule
Composition ◆ → create the object inside the constructor using new. The object is exclusive to this owner.
Aggregation ◇ → receive the object from outside as a constructor parameter. It can be shared.
Dependency - - → → receive as a method parameter only. Never stored as a field. Not part of the object's identity.
4
Self-Aggregation — A Class that Refers to Itself
Now we move to something interesting — self-aggregation. What does it mean? It is aggregation between objects of the same class. The class has a data field whose type is the same class. This might sound strange — but it is very natural once you see the example!
🏫 Classroom Discussion — "How do we assign a supervisor?"
👨🏫
Professor
Let me make it simple. I have three students: Ali, Khaled, and Fahad. Just imagine they have an ID and a name — that is it. Now I want to put Ali as the supervisor of Khaled and Fahad. How should I store that information in the Student class?
🙋
Student
Professor, why not add a field called supervisorId of type int? We just store the ID of the supervisor!
👨🏫
Professor
That could work — but think about it. What if sometime you want to know the supervisor's age? Their GPA? Their address? Any detail about them? If you only store the ID, you would have to search through all students every time to find that information. It becomes very complicated and slow!
📄 Scenario 1 — supervisorId : int ❌ Limited approach
public classStudent {
private int id;
privateString name;
private int supervisorId; // stores only the ID — no other detailspublicStudent(int id, String name) {
this.id = id;
this.name = name;
}
public voidsetSupervisorId(int supervisorId) {
this.supervisorId = supervisorId;
}
public intgetSupervisorId() { return supervisorId; }
public intgetId() { return id; }
publicStringgetName() { return name; }
}
// ── In main ──────────────────────────────────────────────────────────Student ali = newStudent(1, "Ali");
Student khaled = newStudent(2, "Khaled");
Student fahad = newStudent(3, "Fahad");
khaled.setSupervisorId(1); // Ali's ID
fahad.setSupervisorId(1); // Ali's ID// ❌ Problem: to get the supervisor's name you must search manually!int supId = khaled.getSupervisorId(); // returns 1 — but now what?// You need an array or loop to find that student — very slow!Student[] allStudents = {ali, khaled, fahad};
for (Student s : allStudents) {
if (s.getId() == supId) {
System.out.println(s.getName()); // "Ali" — but at what cost?
}
}
👨🏫
Professor
Now — think! A supervisor is also a student, correct? A supervisor IS a Student. So… why not define a data field called supervisor, but make its typeStudent? That gives you the full supervisor object with all their details!
🙋
Students
Wait — a field of type Studentinside the Student class itself?! 🤯 Objects inside objects of the same type!
👨🏫
Professor
Exactly! 🎉 This is called self-aggregation! It is amazing — objects inside objects of the same class. Let me show you how it works in code.
Self-aggregation: Student has a field of type Student — the 0..1 means a student may have zero or one supervisor
public classStudent {
private int id;
privateString name;
privateStudent supervisor; // ← self-aggregation: same class as field type!publicStudent(int id, String name) {
this.id = id;
this.name = name;
// supervisor starts as null — may be assigned later
}
public voidsetSupervisor(Student supervisor) {
this.supervisor = supervisor;
}
publicStudentgetSupervisor() { return supervisor; }
public intgetId() { return id; }
publicStringgetName() { return name; }
}
// ── In main ──────────────────────────────────────────────────────────Student ali = newStudent(1, "Ali");
Student khaled = newStudent(2, "Khaled");
Student fahad = newStudent(3, "Fahad");
// Assign Ali as supervisor for Khaled and Fahad
khaled.setSupervisor(ali);
fahad.setSupervisor(ali);
// Now we can access all supervisor details through the object chain!
System.out.println(khaled.getSupervisor().getName()); // "Ali"
System.out.println(fahad.getSupervisor().getId()); // 1
📦 Objects in memory — chained references:
khaled : Student
id2
name"Khaled"
supervisor→ ali
→
ali : Student
id1
name"Ali"
supervisornull
🔮 You Will See This Again — Linked Lists!
You will meet self-aggregation again in the Data Structures course next semester, when you study Linked Lists. Each Node holds some data and a reference to the nextNode — which is exactly the same pattern as self-aggregation! The concepts you are learning now are the foundation.
5
Multiplicity — How Many Objects Are Involved?
Before we move to the next topic, the professor explained one more concept in UML — multiplicity. This answers the question: "How many objects of a class are involved in a relationship?"
🏫 Classroom Discussion — What is multiplicity?
👨🏫
Professor
In UML, when we draw a relationship between two classes, we can have many-to-many or one-to-many relationships. We need to show the student what this means. For each class involved in a relationship, we write a number — or a range — at its end of the relationship line. This is called multiplicity.
👨🏫
Professor
For example — a Teacher can teach zero to three courses (0..3). Each Course has exactly one teacher (1). A course must have between 5 and 60 students (5..60). And a student can take many courses (*). This is multiplicity!
📐 What is Multiplicity?
Multiplicity specifies how many instances of one class can be associated with one instance of another class. It is written at both ends of a relationship line in UML. Each class involved in a relationship has its multiplicity specified.
Notation
Meaning
Example
1
Exactly one
A course has exactly 1 teacher
0..1
Zero or one (optional)
A student may have 0 or 1 supervisor
* or 0..*
Zero or more
A student can take many courses
1..*
One or more
A faculty must have at least 1 teacher
5..60
Between 5 and 60
A course section has 5 to 60 students
0..3
Zero to three
A teacher teaches 0 to 3 courses
🎓 Example: Teacher → Course → Student
📝 How to Read Multiplicity Labels
Read each label from the perspective of the other class.
The 1 near Teacher means: "from a Course's point of view, it has exactly 1 teacher."
The 0..3 near Course means: "from a Teacher's point of view, they teach 0 to 3 courses."
The 5..60 near Student means: "from a Course's point of view, it has 5 to 60 enrolled students."
The * near Course means: "from a Student's point of view, they can take any number of courses."
✓
Summary
🎉 What We Covered in This Part
🔧
3 Main Relationships: Dependency · Aggregation · Inheritance
"uses" · "has" · "is" — Simple! Aggregation has two strengths: weak (aggregation) and strong (composition).
🔧
Dependency ("uses")
Temporary usage as a method parameter. NOT stored as a field. NOT part of the object's identity. Can be replaced with a static method.
📦
Aggregation ◇ ("has-a", weak)
Contained object survives independently and can be shared (e.g., Address). Created OUTSIDE and passed in. Open diamond in UML.
💎
Composition ◆ ("owns-a", strong)
Contained object cannot exist without the owner (e.g., Name). Created INSIDE the constructor with new. Filled diamond in UML.
🔄
Self-Aggregation
A class with a field of its own type (e.g., Student supervisor inside Student). Objects inside objects of the same type. Foundation for Linked Lists!
🔢
Multiplicity
Specifies how many objects of a class participate in a relationship. Written at both ends of a UML relationship line: 1, 0..1, *, 1..*, 5..60.