Association, Aggregation, and Composition in OOP (with C#)
"How are these classes related?" is one of the most common questions in object-oriented design, and the answer usually comes down to three relationship types: association, aggregation, and composition. They all describe one class referencing another, but the strength of the relationship, and what happens to one object when the other is destroyed, is different for each.
Association - two classes are related, but neither owns the other.
Aggregation - a "has-a" relationship where the child can exist independently ("owns a", weak).
Composition - a "has-a" relationship where the child cannot exist without the parent (strong).
Association: Two Classes Simply Know About Each Other
Association is the most general relationship. One object uses or interacts with another, but there is no ownership in either direction. Both objects are created and destroyed independently.
public class Teacher
{
public string Name { get; set; }
}
public class Student
{
public string Name { get; set; }
public Teacher Teacher { get; set; }
}
A Student is associated with a Teacher, but the two are not tied together. The same Teacher instance could be associated with many students, and if a Student object is discarded, the Teacher is completely unaffected.
var teacher = new Teacher { Name = "Mrs. Alvarez" };
var student1 = new Student { Name = "Sam", Teacher = teacher };
var student2 = new Student { Name = "Priya", Teacher = teacher };
Aggregation: "Has-A" With Independent Lifetimes
Aggregation is a special form of association that represents a whole/part relationship, where the "whole" holds a collection of "parts", but those parts can exist on their own and can even be shared between wholes.
public class Engineer
{
public string Name { get; set; }
}
public class Team
{
public string Name { get; set; }
public List<Engineer> Engineers { get; set; } = new List<Engineer>();
}
An Engineer can be added to a Team, but the engineer is created independently, outside of the team, and passed in.
var alice = new Engineer { Name = "Alice" };
var bob = new Engineer { Name = "Bob" };
var team = new Team { Name = "Platform Team" };
team.Engineers.Add(alice);
team.Engineers.Add(bob);
If the Team object is discarded, alice and bob keep existing. They could just as easily be moved to a different team.
team = null; // Alice and Bob still exist, referenced elsewhere
Composition: "Has-A" With a Shared Lifetime
Composition is a stronger whole/part relationship. The part is created and owned by the whole, and it has no meaningful existence outside of it. When the owning object goes away, the parts go away with it.
public class Room
{
public string Name { get; set; }
}
public class House
{
public string Address { get; set; }
private readonly List<Room> _rooms = new List<Room>();
public House(string address)
{
Address = address;
_rooms.Add(new Room { Name = "Kitchen" });
_rooms.Add(new Room { Name = "Living Room" });
}
public IReadOnlyList<Room> Rooms => _rooms;
}
The Room objects are constructed inside the House constructor. There is no way to create a Room that belongs to this house from outside of it, and there is no way to move a Room to a different House.
var house = new House("221B Baker Street");
Console.WriteLine(house.Rooms[0].Name); // Kitchen
Once house is discarded, nothing else references its Room objects, so they become eligible for garbage collection along with it.
house = null; // Kitchen and Living Room become eligible for garbage collection too
Comparing the Three Side by Side
Association:
Student ───────────────► Teacher
no ownership, independent lifetimes
Aggregation:
Team ◇──────────────► Engineer
whole/part, but part can outlive the whole
Composition:
House ◆──────────────► Room
whole/part, part cannot outlive the whole
In UML diagrams, aggregation is drawn with a hollow diamond on the "whole" side, and composition with a filled diamond, which is a useful way to remember the difference: hollow means the part can be hollowed out and used elsewhere, filled means it is permanently part of the whole.
Why the Distinction Matters
This is not just an academic exercise. The relationship type affects how you write constructors, how you manage object lifetimes, and how you think about disposal:
- Association: classes reference each other, but neither is responsible for creating or destroying the other.
- Aggregation: the container holds references to objects created elsewhere, so removing an item from the container should not destroy it.
- Composition: the owner is responsible for creating its parts, and often for disposing of them too, for example implementing
IDisposableto clean up composed objects.
public class House : IDisposable
{
private readonly List<Room> _rooms = new List<Room>();
// ... constructor as before ...
public void Dispose()
{
// Composition often implies the owner cleans up its parts.
_rooms.Clear();
}
}
Final Mental Model
- Association: "uses-a" - a loose relationship between independent objects.
- Aggregation: "has-a", weak ownership - the part can exist and be reused without the whole.
- Composition: "has-a", strong ownership - the part is created by the whole and dies with it.
Association Student references a Teacher that exists independently.
Aggregation Team holds Engineers that exist independently and could belong to another team.
Composition House creates and owns Rooms that cannot exist without it.

















