Association vs. Composition: The "Has-A" Relationship
In Object-Oriented Programming, we often describe how objects relate to one another. Your code examples perfectly demonstrate the two most common ways one class can "have" another class: Association (Aggregation) and Composition.
1. Association (Aggregation): Weak Relationship
public class Main {
// Player class
static class Player {
public String playerName;
Player(String playerName) {
this.playerName = playerName;
}
public void printPlayerName() {
System.out.println(this.playerName);
}
}
// Team class
static class Team {
public int playerNumber;
public Player pl;
Team(int playerNumber, Player pl) {
this.playerNumber = playerNumber;
this.pl = pl;
}
}
// Main method
public static void main(String[] args) {
Player pl = new Player("new player");
Team tmDz = new Team(55, pl);
pl.printPlayerName();
// Extra (optional)
System.out.println("Team player number: " + tmDz.playerNumber);
}
}
In Example Above, the team and player exist independently.
- The Logic: A player can exist without a team, and a team can exist without that specific player.
- The Implementation: You create the
playerfirst, then pass it into theteamconstructor. - The Lifetime: If you delete the
tmDzobject, theplobject still exists in memory because it was created outside the team.
// Weak link: 'pl' is born outside the team
player pl = new player("new player");
team tmDz = new team(55, pl);
2. Composition: Strong Relationship
public class Main {
// Engine class
static class Engine {
String type;
Engine(String type) {
this.type = type;
}
@Override
public String toString() {
return type + " engine";
}
}
// Car class (has Engine)
static class Car {
Engine e;
Car(String engineType) {
this.e = new Engine(engineType); // Composition
}
@Override
public String toString() {
return "Car with " + e;
}
}
// Main method
public static void main(String[] args) {
// Create Car → Engine is created inside it
Car car = new Car("V8");
System.out.println(car);
}
}
In Example Above, the Car and Engine are tightly bound. This is a "death relationship."
- The Logic: An engine (in this specific context) is part of the car. It doesn't make sense for this engine to exist floating around without a car body.
- The Implementation: You create the
Engineinside theCarconstructor. The outside world doesn't even see the engine being created. - The Lifetime: If the
carobject is destroyed (garbage collected), thee(Engine) is destroyed with it because nothing else has a reference to it.
// Strong link: 'e' is born inside the Car
Car(String engineType) {
this.e = new Engine(engineType);
}
3. Comparison Summary
| Feature | Association (Ex 53) | Composition (Ex 54) |
|---|---|---|
| Relationship | Weak "Has-A" | Strong "Has-A" (Part-of) |
| Creation | Created outside the container | Created inside the container |
| Dependency | Independent | Dependent |
| Lifetime | Child lives if Parent dies | Child dies if Parent dies |
💡 Practical Tip for Developers
- Use Association when objects belong to multiple containers (e.g., a
Teacherin aSchool). - Use Composition when the child object is a physical or logical part of the parent (e.g., a
Roomin aHouseor aHeaderin aDocument).
💡 Challenge: The Personal Computer
- Create a class
Motherboard. - Create a class
Computer. - Inside the
Computerconstructor, create a newMotherboardobject (Composition). - Create a class
USBDevice. - Create a method in
ComputercalledplugIn(USBDevice device)that takes a device created inmain(Association).
How does the lifetime of the Motherboard differ from the USBDevice if the Computer is shut down?