Loading learning content...
Consider the relationship between a house and its rooms. Can a room exist floating in space, unattached to any building? In practical terms, no—a room's identity, boundaries, and very existence are defined by the building that contains it. Destroy the building, and the rooms are destroyed with it.
This is fundamentally different from, say, furniture in those rooms. Furniture can exist independently—moved to another building, stored in a warehouse, or sold. But the rooms themselves? They're inseparable from the structure.
This distinction between dependent parts (like rooms) and independent parts (like furniture) is captured in UML through two different relationship types: composition and aggregation. Having covered aggregation, we now turn to its stronger sibling—composition.
By the end of this page, you will understand what composition represents and how it differs from aggregation, how to draw composition using the filled diamond notation, the concept of lifecycle dependency between whole and parts, and when composition is the correct modeling choice.
Composition is the strongest form of association in UML—a whole-part relationship where the parts have a dependent lifecycle. The parts cannot exist independently of the whole. When the whole is destroyed, all its composed parts are destroyed with it.
The defining characteristics of composition:
Composition in code terms:
When a whole has a composition relationship with its parts, the whole creates, owns, and destroys the parts:
public class Order {
private List<LineItem> items; // Composition
public void addItem(String productId, int quantity, double price) {
// Order CREATES the LineItem
LineItem item = new LineItem(productId, quantity, price);
items.add(item);
}
// When Order is deleted, all LineItems are implicitly deleted
// LineItems have no independent existence
}
The Order creates LineItem objects internally. A LineItem without an Order is meaningless—it's just raw data about quantity and price with no context. When the order is cancelled (deleted), the line items cease to exist.
Ask yourself: 'If the whole is destroyed, do the parts make any sense on their own?' If no, it's likely composition. A LineItem without its Order is meaningless. A Room without its Building is impossible. A Finger without its Hand doesn't function.
In UML, composition is represented by a solid line with a filled (solid) diamond at the "whole" end. The filled diamond—compared to aggregation's hollow diamond—visually emphasizes the stronger, more exclusive nature of the relationship.
Basic composition visualization:
Key elements of composition notation:
| Element | Description |
|---|---|
| Filled diamond (◆) | Attached to the "whole" (composite) class |
| Solid line | Connects whole to part |
| Multiplicity | Still applies; the whole-side is always 1 (exactly one owner) |
| Navigability | Typically unidirectional from whole to parts |
Complete composition example with multiplicity:
In composition, the multiplicity on the whole side is always exactly 1. This reflects exclusive ownership—a part cannot belong to multiple wholes. The multiplicity on the part side can vary (0..1, 1, *, etc.) depending on how many parts the whole contains.
The distinction between composition and aggregation is one of the most important—and most frequently confused—concepts in UML. Let's clarify it definitively:
| Aspect | Composition (◆) | Aggregation (◇) |
|---|---|---|
| Lifecycle | Dependent—parts die with whole | Independent—parts survive whole |
| Ownership | Exclusive—one owner only | Potentially shared—multiple owners |
| Creation | Whole creates parts | Whole receives existing parts |
| Deletion | Cascade—delete whole deletes parts | No cascade—parts remain |
| Diamond | Filled (solid) | Hollow (empty) |
| Strength | Strongest relationship | Weaker than composition |
Ask: 'Can this part be transferred to another whole?' If yes (Player to another Team, Book to another Library), it's aggregation. If no (LineItem can't move to another Order—it would need to be recreated), it's composition.
Identifying composition relationships requires careful analysis of domain semantics. Here's a systematic approach:
The composition identification checklist:
Practical example: Document Editor System
Let's analyze relationships in a document processing system:
The same concept might be composition in one system and aggregation in another. In a simple document editor, Comment is composed. In a collaborative system where comments persist independently and link to multiple documents, Comment might be aggregated. Always analyze your specific domain context.
Composition relationships often form hierarchical trees where deleting a node cascades deletion through all descendants. This pattern is common in UI frameworks, document models, and organizational structures.
Example: GUI Component Hierarchy
Cascade deletion semantics:
In this hierarchy:
Window deletes all its PanelsPanel deletes all its Buttons, Labels, and TextFieldsSelf-referential composition:
Composition can also be recursive, creating tree structures of the same type:
When deleting a Folder in this structure, all contained subfolders (and their contents) and files are recursively deleted. This is the expected behavior for composition—the entire subtree is removed. Implementation must handle this cascade correctly.
Translating composition from UML to code requires careful attention to lifecycle management.
Object creation and ownership:
In composition, the whole typically creates parts internally or receives them through factory methods—not as external dependencies:
123456789101112131415161718192021222324252627282930
public class Order { private final String orderId; private final List<LineItem> lineItems; // Composition public Order(String orderId) { this.orderId = orderId; this.lineItems = new ArrayList<>(); } // Order CREATES LineItems - they don't come from outside public LineItem addItem(Product product, int quantity) { LineItem item = new LineItem( this.orderId, // ties item to this order product.getId(), quantity, product.getPrice() ); lineItems.add(item); return item; } // LineItems don't escape - return copies or read-only views public List<LineItem> getLineItems() { return Collections.unmodifiableList(lineItems); } // When Order is deleted, LineItems go with it // No need for explicit cleanup if using GC // In DB: ON DELETE CASCADE}Database representation:
In relational databases, composition is enforced through:
| Pattern | Implementation | Effect |
|---|---|---|
| Foreign key | line_item.order_id NOT NULL | Part must have owner |
| Cascade delete | ON DELETE CASCADE | Delete order removes items |
| No shared ownership | FK to single table only | One owner per part |
Composed parts should not escape the whole. Return immutable views or copies instead of direct references. This prevents external code from holding references to parts that might be deleted when the whole is destroyed.
Certain composition patterns recur across different domains. Recognizing these accelerates design decisions.
Pattern 1: Value Object Composition
The whole contains value objects that have no identity outside the whole.
| Entity (Whole) | Value Object (Part) | Characteristic |
|---|---|---|
| Person | Address | Address has no meaning without Person |
| Order | Money (total) | Amount belongs to this specific order |
| Event | DateTimeRange | Time range is intrinsic to event |
| Product | Dimensions | Dimensions are properties of the product |
Pattern 2: Transaction/Line-Item Composition
A header record owns detail records that are meaningless in isolation.
| Header (Whole) | Detail (Part) | Domain |
|---|---|---|
| Order | LineItem | E-commerce |
| Invoice | InvoiceLine | Accounting |
| ShoppingCart | CartItem | Retail |
| Prescription | PrescriptionItem | Healthcare |
Pattern 3: Container/Content Composition
A logical or physical container owns its contents.
| Container (Whole) | Content (Part) | Relationship |
|---|---|---|
| Window | View components | UI framework |
| Document | Paragraphs | Document editors |
| Attachments | Messaging systems | |
| ChatRoom | Messages | Communication apps |
When modeling a new domain, ask: 'Is this a value object owned by an entity? A header with detail lines? A container with owned contents?' Identifying the pattern quickly guides the correct relationship type.
We've explored composition as the strongest form of association. Let's consolidate the key takeaways:
What's next:
We've now covered the whole-part relationships (aggregation and composition). Next, we'll examine inheritance—the "is-a" relationship represented by a hollow triangle arrow. Inheritance represents generalization/specialization hierarchies where subclasses extend and specialize their parent classes.
You now understand composition as the strongest whole-part relationship with dependent lifecycles, represented by a filled diamond. Next, we'll examine inheritance—the generalization relationship that enables type hierarchies and polymorphism.