UML Association Ends: Choosing Navigability and Ownership Before You Code
Association ends decide how objects find each other and who owns whom. Treat multiplicity, navigability, aggregation, and composition as implementation decisions, not just diagram notation.
07 Aug 2025, 01:02 UTC

The problem: a line between boxes is not enough
Your team sketches a class diagram for an order system. Someone draws a line between Order and OrderItem, labels it contains, and calls it done. Weeks later, the code has Order holding a list of items and each OrderItem holding a reference back to its order. JSON serialization loops forever, and deleting an order leaves orphaned items in memory.
The missing piece was not the line itself. It was the association ends: multiplicity, navigability, and ownership. In UML 2.x, each end of an association declares how many objects participate and whether objects can traverse the link in a given direction. Treating these as implementation decisions up front prevents coupled object graphs and surprise lifecycle bugs.
What each end declares
An association connects two classes, but the semantics live at the ends.
- Multiplicity states how many instances of one class can link to a single instance of the other, such as
0..*or1. It is a design constraint, not runtime validation. - Navigability indicates which direction objects can traverse. An arrow at one end means objects at the opposite end can find their related objects; no arrow usually means the link is unidirectional or unspecified.
- Aggregation (hollow diamond) suggests shared ownership, where the part can exist independently of the whole.
- Composition (filled diamond) indicates strong whole-part ownership. The part's lifetime is tied to the whole, though UML itself does not delete anything.
These properties appear in exported XMI as association-end attributes, which code generators may turn into fields, collections, or foreign keys.
Navigability shapes the object graph
A bidirectional association lets both sides reach each other. That simplifies domain queries—an item can find its order, and an order can list its items—but it creates circular references. Serializers may loop, and garbage-collected languages can keep objects alive longer than intended because each side holds a reference to the other.
A unidirectional association reduces coupling. If only Order navigates to OrderItem, the item does not need an order reference. Reverse lookups then require a repository method, query, or navigation class instead of a direct pointer. This maps cleanly to a foreign key on the item table pointing to the order.
Ownership is about lifecycle, not just drawing style
Composition says an OrderItem does not make sense without its Order. Aggregation says a Product might appear in many orders and outlive any single one. Neither keyword tells the runtime to destroy objects. In Java or C#, deleting an order does not automatically remove its items; your code must do that, or rely on repository logic and garbage collection.
Choose composition when the part cannot exist independently and the whole controls creation and deletion. Choose aggregation or plain association when the part has its own identity and lifecycle.
Worked example: Order and OrderItem
Model Order and OrderItem with these ends:
| End | Multiplicity | Navigable | Ownership |
|---|---|---|---|
| Order side | 1 | Yes | Composition whole |
| OrderItem side | 0..* | No | Composition part |
This says an order contains zero or more items, and items cannot navigate back to the order. In Java-like code, that might look like:
public class Order {
private final List<OrderItem> items = new ArrayList<>();
public void addItem(OrderItem item) {
items.add(item);
}
public List<OrderItem> getItems() {
return List.copyOf(items);
}
}
public class OrderItem {
private final String sku;
private final int quantity;
public OrderItem(String sku, int quantity) {
this.sku = sku;
this.quantity = quantity;
}
}
Notice OrderItem has no field pointing back to Order. If you need to find an order from an item later, query an order repository by item identifier instead of traversing a back-reference.
To verify the model, export it to XMI and inspect the association-end properties. From a terminal in the folder containing your exported file:
grep -n "ownedEnd" order-model.xmi
Run this where you have read access to order-model.xmi. The placeholder is your actual XMI filename. Expected output includes end declarations with multiplicity and navigability attributes. Risk: tool vendors use different XMI namespace prefixes, so the exact element names may vary; compare against your tool's documentation rather than assuming a standard tag name.
Limitations and how to check the result
UML multiplicity does not enforce cardinality at runtime. Your application code must reject an order with zero items if the business rule requires one. Composition does not mean automatic deletion in garbage-collected languages. Bidirectional links can generate circular references that complicate serialization. Tool-specific profiles may add stereotypes that do not survive export to another modeling tool.
Practical verification: after changing an association end, regenerate code or inspect the hand-written mapping, then confirm that reverse navigation exists only where the model declares it. If you declared unidirectional, search the codebase for back-references. If you declared composition, confirm the whole's delete path removes or orphans the parts as intended.
Closing checklist
- Decide which direction actually needs navigation before drawing an arrow.
- Use composition only when the part's lifecycle is controlled by the whole.
- Do not rely on UML multiplicity to validate data at runtime.
- Export XMI and check association-end properties against the implemented code.
- Test serialization and deletion paths for bidirectional associations.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.