🇸🇦 العربية
CPCS203  ·  Module 05  ·  Part 2 of 3

🔗 Object Relationships

Dependency · Aggregation · Composition · Self-Aggregation · Multiplicity

🔧 Dependency 📦 Aggregation 💎 Composition 🔄 Self-Aggregation 🔢 Multiplicity
📋 Table of Contents
  1. Object Relationships — The Big Picture
  2. Dependency — "uses"
  3. Aggregation & Composition — "has"
  4. Self-Aggregation
  5. Multiplicity — How Many Objects Are Involved?
1
Object Relationships — The Big Picture
🏫 The Professor Introduces Relationships
👨‍🏫
Professor
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!

Dependency says "uses." Aggregation says "has." Inheritance says "is."
🔧
Dependency
"uses"
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?
Student -id : int -name : Name -address : Address -marks : int[] +Student(id: int, first: String, last: String, address: Address) +getId() : int +getFullName() : String +getAddress() : Address +getMarks() : int[] +calculateBMI(calc: BMICalculator) : double Name -firstName : String -lastName : String +Name(first: String, last: String) +getFirstName() : String +getLastName() : String +getFullName() : String Address -street : String -city : String -unit : int +Address(street: String, city: String, unit: int) +getStreet() : String +getCity() : String +getUnit() : int BMICalculator -weight : double -height : double +BMICalculator(weight: double, height: double) +getBMI() : double +getBMI(weight: double, height: double) : double Aggregating class Collects Name, Address as fields. Uses BMICalculator temporarily. Composition ◆ Created inside Student constructor. Cannot exist without a Student. Dies when Student dies. Aggregation ◇ Created outside, passed in. Can be shared by many students. Survives independently. Dependency Passed as a method parameter. NOT stored as a field. Not part of student's identity. Can also be made static. composition ◆ owns 1 1 aggregation ◇ has * 1 «uses» dependency

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.

Student «uses» BMICalculator

Dashed open arrow = Dependency ("uses" relationship)

📄 BMICalculator.java — used as a dependency
public class BMICalculator { private double weight; // in kg private double height; // in meters public BMICalculator(double weight, double height) { this.weight = weight; this.height = height; } public double getBMI() { return weight / (height * height); } } // In Student class — dependency: BMICalculator is a method PARAMETER, not a field public double calculateBMI(BMICalculator calc) { return calc.getBMI(); // used temporarily — NOT stored as a field! } // ── OR using static method (even cleaner — no object needed at all) ── public class BMICalculator { public static double getBMI(double weight, double height) { return weight / (height * height); } } // In Student: no object created, just call the calculator directly double 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
Student -id : int -name : Name -address : Address -marks : int[] +Student(id: int, first: String, last: String, address: Address) +getId() : int +getFullName() : String +getAddress() : Address +getMarks() : int[] +calculateBMI(calc: BMICalculator) : double Name -firstName : String -lastName : String +Name(first: String, last: String) +getFirstName() : String +getLastName() : String +getFullName() : String Address -street : String -city : String -unit : int +Address(street: String, city: String, unit: int) +getStreet() : String +getCity() : String +getUnit() : int BMICalculator -weight : double -height : double +BMICalculator(weight: double, height: double) +getBMI() : double +getBMI(weight: double, height: double) : double Aggregating class Collects Name, Address as fields. Uses BMICalculator temporarily. Composition ◆ Created inside Student constructor. Cannot exist without a Student. Dies when Student dies. Aggregation ◇ Created outside, passed in. Can be shared by many students. Survives independently. Dependency Passed as a method parameter. NOT stored as a field. Not part of student's identity. Can also be made static. composition ◆ owns 1 1 aggregation ◇ has * 1 «uses» dependency

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.
📄 Name.java
public class Name { private String firstName; private String lastName; public Name(String first, String last) { this.firstName = first; this.lastName = last; } public String getFullName() { return firstName + " " + lastName; } }
📄 Address.java
public class Address { private String street; private String city; private int unit; public Address(String street, String city, int unit) { this.street = street; this.city = city; this.unit = unit; } public String getCity() { return city; } public String getStreet() { return street; } }
📄 Student.java — composition vs aggregation in code
public class Student { private int id; private Name name; // ◆ COMPOSITION — will be created INSIDE private Address address; // ◇ AGGREGATION — will be received from OUTSIDE // Name is created HERE inside the constructor → composition // Address is passed in from outside → aggregation public Student(int id, String first, String last, Address address) { this.id = id; this.name = new Name(first, last); // ◆ composition: created inside this.address = address; // ◇ aggregation: shared object from outside } public String getFullName() { return name.getFullName(); } public Address getAddress() { return address; } // Dependency: BMICalculator used temporarily as a method parameter — NOT stored public double calculateBMI(BMICalculator calc) { return calc.getBMI(); } } // ── In main ──────────────────────────────────────────────────────────── // One address object — shared by multiple students (aggregation) Address sharedAddress = new Address("Al-Jami'a St", "Jeddah", 100); Student ali = new Student(1, "Ali", "Fahad", sharedAddress); Student khalid = new Student(2, "Khalid", "Nasser", sharedAddress); Student fahad = new Student(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 class Student { private int id; private String name; private int supervisorId; // stores only the ID — no other details public Student(int id, String name) { this.id = id; this.name = name; } public void setSupervisorId(int supervisorId) { this.supervisorId = supervisorId; } public int getSupervisorId() { return supervisorId; } public int getId() { return id; } public String getName() { return name; } } // ── In main ────────────────────────────────────────────────────────── Student ali = new Student(1, "Ali"); Student khaled = new Student(2, "Khaled"); Student fahad = new Student(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 type Student? That gives you the full supervisor object with all their details!
🙋
Students
Wait — a field of type Student inside 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.
Student -id : int -name : String -supervisor : Student +Student(id: int, name: String) +setSupervisor(s: Student) : void +getSupervisor() : Student +getId() : int +getName() : String supervisor 0..1 0..1

Self-aggregation: Student has a field of type Student — the 0..1 means a student may have zero or one supervisor

📄 Scenario 2 — supervisor : Student  ✅ Self-aggregation — correct approach
public class Student { private int id; private String name; private Student supervisor; // ← self-aggregation: same class as field type! public Student(int id, String name) { this.id = id; this.name = name; // supervisor starts as null — may be assigned later } public void setSupervisor(Student supervisor) { this.supervisor = supervisor; } public Student getSupervisor() { return supervisor; } public int getId() { return id; } public String getName() { return name; } } // ── In main ────────────────────────────────────────────────────────── Student ali = new Student(1, "Ali"); Student khaled = new Student(2, "Khaled"); Student fahad = new Student(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 next Node — 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.

NotationMeaningExample
1Exactly oneA course has exactly 1 teacher
0..1Zero or one (optional)A student may have 0 or 1 supervisor
* or 0..*Zero or moreA student can take many courses
1..*One or moreA faculty must have at least 1 teacher
5..60Between 5 and 60A course section has 5 to 60 students
0..3Zero to threeA teacher teaches 0 to 3 courses

🎓 Example: Teacher → Course → Student

Teacher - name : String 1 0..3 Course - courseCode : String * 5..60 Student - id : int 1 teacher teaches 0..3 courses a student takes many (*) courses; each course has 5..60 students
📝 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.