B3.2.4
Explain the role of composition and aggregation in class relationships
In OOP, classes can relate in different ways:
Overview
In OOP, classes can relate in different ways:
is-arelationship (inheritance)has-arelationship (aggregation)part-ofrelationship (composition)
Composition and aggregation both model ownership/containment, but with different dependency strength.
Aggregation (has-a)
Aggregation is a weak ownership relationship:
- One class contains or references another
- Both objects can exist independently
Example from the notes:
Playlisthas manySongobjects- A
Songcan still exist without a specificPlaylist
UML hint: aggregation is shown with a hollow diamond at the owner side.
Composition (part-of)
Composition is a strong ownership relationship:
- One object is a required part of another
- Part lifecycle depends on whole lifecycle
- If the whole is deleted, its parts are deleted too
Example from the notes:
BookcontainsChapterobjectsChapterdoes not meaningfully exist without itsBook
UML hint: composition is shown with a filled diamond at the owner side.
Aggregation vs Composition
| Aspect | Aggregation | Composition |
|---|---|---|
| Dependency strength | Weak | Strong |
| Independent lifecycle | Yes | No |
| Ownership | Shared/loose | Exclusive/strong |
| Delete whole object | Parts may still exist | Parts are typically removed |
| Common phrase | has-a | part-of |
Why This Matters in Design
- Helps model real systems correctly (loose vs tight ownership)
- Improves maintainability by clarifying responsibilities
- Prevents lifecycle bugs (e.g., orphan objects or accidental shared state)
- Makes UML and code structure consistent
Python Examples
1. Aggregation Example
class Song:
def __init__(self, title: str):
self.title = title
class Playlist:
def __init__(self, name: str):
self.name = name
self.songs: list[Song] = []
def add_song(self, song: Song):
self.songs.append(song)
song = Song("Imagine")
playlist = Playlist("Favorites")
playlist.add_song(song)
# song can still exist even if playlist is deleted
2. Composition Example
class Chapter:
def __init__(self, title: str):
self.title = title
class Book:
def __init__(self, title: str, chapter_titles: list[str]):
self.title = title
# chapters are created as an internal part of Book
self.chapters = [Chapter(t) for t in chapter_titles]
book = Book("OOP Basics", ["Intro", "Classes", "Relationships"])