Associations represent domain-significant relationships—Employee X supervises Employee Y, Employee X is employed by Company Z, Company Z manufactures Product P, etc.
Associations are represented by lines connecting classes:
Notes:
It is also possible to represent n-ary relationships such as Employee X is employed by Company Y which manufactures Product P. But not all tools support the notation for this.
In the case of binary relationships there is no notation so show the direction of the relationship.
Associations are also classifiers. Their instances are called links. Links link together related instances of the classes.
For example, assume Smith supervises Jones. Both work for a company called Acme which manufactured some widget. We could represent this using an object diagram consisting of four objects and four links. Link s is an instance of the supervises association, e1 and e2 are instances of the employed-by association, and m is an instance of the manufactures association:
A binary association has two endpoints. (An N-ary association has N endpoints.)
From the UML meta-model:
For example, consider the association representing the relationship Physician X treats Patient Y:
The treats association has two endpoints named doctor and patient. These names are how instances of one class refer to instances of the other. They are often translated into fields by code generators:
class Physician {
String name;
Patient patient;
// ...
}
class Patient {
Physician doctor;
// ...
}
Note that both attributes and association endpoints are translated into fields by code generators. I chose to represent the name property of a physician as an attribute because its type—String—is not represented as a class in my model. String does not belong to the health-care domain. It is not domain-significant.
The scope of any UML element, including an endpoint, can either be public (globally visible), private (visible only within the referencing class, this should be the default), package (visible to all classes within the package), and protected (visible to all sub-classes).
Multiplicity refers to the number of instances of a class that are linked to the referring class.
For example, how many patients does a physician treat? One? Three to five? Three or five? Zero or more?
Navigability answers the question: Can we navigate from a physician to each of her patients?
Part-whole relationships, called aggregations in UML, occur frequently in domain models. For example:
A component is part of an assembly
A member is part of a collection
UML recognizes two types of aggregations: shared and composite.
In a shared aggregation the part can be shared by wholes. Destroying the whole does not destroy the parts. A hollow diamond on the whole side of the association is used to indicate shared aggregation. For example:
In composite aggregation parts are not shared. Destroying the whole destroys the parts. A solid diamond on the whole side of the association is used to indicate composite aggregation. For example:
In C++ we might distinguish shared and composite aggregation as follows:
// composite aggregation
class Whole {
Part part;
// ...
};
// shared aggregation
class Whole {
Part* part;
// ...
};
Example:
We may consider the relationships between a document and its author and table of contents as part-whole relationships.
A document has an author and a table of contents. It shares the author with other documents. Destroying the document does not destroy the author. The table of contents is not shared by other documents. Destroying the document does destroy the table of contents.
Here's a possible C++ implementation:
class Document {
ContentTable toc;
Person* author;
// ...
};
Warning: Aggregation can be a semantic can of worms without much impact on the code. It has been described by the creators of UML as a placebo. Unless directed otherwise, avoid using aggregation.
Member-collection relationships also come in four flavors: ordered/unique (ordered set), unordered/unique (set), ordered/non-unique (list) and unordered/non-unique (multi-set). A collection is ordered if the ordering is domain-significant. Otherwise it should be unordered.
Example:
Here's the Java code that should be generated:
class Team {
Set<Athlete> players;
// ...
}
class Itinerary {
List<Airport> stops;
// ...
}
class Showing {
LinkedHashSet<Date> dates;
// ...
}
class Number {
com.google.common.collect.Multiset<Prime>
factors; // multisets not available in standard Java
// ...
}
A member-collection relationship is qualified if members are indexed by unique keys:
Here's the Java code that might be generated:
class PhoneBook {
Map<String, Person> contacts;
// ...
}