In object-oriented design, classes interact to model real-world systems. Understanding how objects connect through Association, Aggregation, and Composition is essential for creating clean, modular, and maintainable software architectures.
Relationships between classes generally fall into three core categories based on ownership and lifecycle coupling:
Association defines a connection or communication link between two independent classes. Objects collaborate through pointers, references, or collections without owning each other's lifecycles.
Person and Passport).
Teacher and Student).
Student and Course).
import java.util.List;
class Passport {
private String passportNumber;
public Passport(String number) { this.passportNumber = number; }
}
class Person {
private String name;
private Passport passport; // One-to-One Association
public Person(String name, Passport passport) {
this.name = name;
this.passport = passport;
}
}
#include <iostream>
#include <string>
using namespace std;
class Passport {
private:
string passportNumber;
public:
Passport(string number) : passportNumber(number) {}
};
class Person {
private:
string name;
Passport* passport; // One-to-One Association via pointer
public:
Person(string name, Passport* p) : name(name), passport(p) {}
};
class Passport:
def __init__(self, number):
self.passport_number = number
class Person:
def __init__(self, name, passport: Passport):
self.name = name
self.passport = passport # One-to-One Association
Aggregation is a specialized form of association that represents a whole-part ("has-a") relationship. The bond is weak: if the container ("whole") is destroyed, the contained items ("parts") continue to exist independently.
Example: A Department contains multiple Employee objects.
If the Department is deleted, the Employee objects still exist.
import java.util.List;
class Employee {
private String name;
public Employee(String name) { this.name = name; }
}
class Department {
private List<Employee> employees; // Aggregation
// Employees are created outside and passed in
public Department(List<Employee> employees) {
this.employees = employees;
}
}
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Employee {
private:
string name;
public:
Employee(string name) : name(name) {}
};
class Department {
private:
vector<Employee> employees; // Aggregation
public:
Department(vector<Employee> employees) : employees(employees) {}
};
from typing import List
class Employee:
def __init__(self, name):
self.__name = name
class Department:
def __init__(self, employees: List[Employee]):
self.__employees = employees # Aggregation (employees created externally)
Composition is a strict form of aggregation representing a part-of relationship. The container owns the child objects. If the container ("whole") is destroyed, all its child components ("parts") are automatically destroyed with it.
Example: A House consists of Room objects. The
Room instances are created inside the House constructor and cannot
exist without the House.
import java.util.ArrayList;
import java.util.List;
class Room {
private String name;
public Room(String name) { this.name = name; }
}
class House {
private List<Room> rooms; // Composition
public House() {
rooms = new ArrayList<>();
// Rooms created internally — lifecycle tied to House
rooms.add(new Room("Living Room"));
rooms.add(new Room("Bedroom"));
}
}
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Room {
private:
string name;
public:
Room(string name) : name(name) {}
};
class House {
private:
vector<Room> rooms; // Composition
public:
House() {
// Rooms constructed inside House — destroyed when House is destroyed
rooms.push_back(Room("Living Room"));
rooms.push_back(Room("Bedroom"));
}
};
class Room:
def __init__(self, name):
self.__name = name
class House:
def __init__(self):
self.__rooms = []
# Rooms constructed inside House — lifecycle tied to House
self.__rooms.append(Room("Living Room"))
self.__rooms.append(Room("Bedroom"))
Classes in real software often participate in multiple relationship types simultaneously:
Library has an Aggregation relationship with
Book (books can exist outside or move between libraries).
Book has a Composition relationship with
Chapter (destroying a book destroys its chapters).
| Aspect | Association | Aggregation | Composition |
|---|---|---|---|
| Relationship Type | General interaction ("uses-a") | Weak whole-part ("has-a") | Strong whole-part ("part-of") |
| Ownership | No ownership | Contains, but does not own lifecycle | Strict ownership of child lifecycle |
| Lifecycle Dependency | Independent lifecycles | Contained object outlives container | Contained object dies with owner |
| Real-World Example | Teacher & Student |
Department & Employee |
House & Room / Car & Engine
|
Which relationship type exists between a House and its
Room instances?
What distinguishes Aggregation from Composition?
Association ⇒ General interaction ("uses-a") between independent objects
Aggregation ⇒ Weak whole-part ("has-a") ; independent lifecycles
Composition ⇒ Strong whole-part ("part-of") ; owner controls child lifecycle
a) One-to-One ⇒ Person — Passport
b) One-to-Many ⇒ Teacher — Student
c) Many-to-Many ⇒ Student — Course
Aggregation ⇒ Parts created externally and passed in (eg Department has
Employee list)
Composition ⇒ Parts created inside container constructor (eg House creates
Room list)
Lifecycle rule ⇒ Destroying container destroys parts in composition, NOT in aggregation
Primary source: Oracle Java Tutorials — Interfaces & Inheritance & cppreference — Class Design Patterns. Ask me anything that's unclear.
Questions? Ask your agent — you can follow up on any concept, quiz answer, or how this applies to a specific coding problem. Review the Java glossary or syntax quick reference for a compressed overview.