10.3. Constructive Relationships

Time: 00:02:03 | Download: Large, Large (CC), Small | Streaming (CC) | Slides (PDF)

An earlier example demonstrated how the inheritance relationship between two classes, a Car and a Sedan, could be described as an "is-a" relationship: a Sedan is-a Car. The example further suggested that it "didn't sound right" to say that a sedan has-a Car or that a Car has-a Sedan. Nevertheless, the "has-a" phrase is useful in many problem solutions, suggesting a constructive relationship between two classes. But unlike inheritance, which is fundamental to object orientation and implemented with dedicated syntax, constructive relationships are implemented with class-scope or member variables. We can create three different relationships depending on how we define and where we place the variables.

CompositionAggregationAssociation
A UML class diagram showing three classes related by composition. The UML composition connector is a line with a solid or filled-in diamond shape at one end, while the other is plain or undecorated. The diamond always attaches to the whole class, and the undecorated end attaches to the part class. In this example, Car is the whole class with two parts: Engine and Transmission. A UML class diagram showing three classes related by aggregation. The UML aggregation connector is a line with a hollow or outlined diamond shape at one end, while the other is plain or undecorated. The diamond always attaches to the whole class, and the undecorated end attaches to the part class. In this example, Car is the whole class with two parts: Engine and Transmission. Two UML classes, contractor and project, connected by an undecorated line, indicating association.
Constructive or "has-a" relationships. The constructive relationships connect classes - they help construct object-oriented programs. Aggregation and composition represent whole-part relationships in C++ programs and UML class diagrams. The UML composition and aggregation symbols are similar, suggesting that the relationships are similar. In C++, we implement aggregation with a pointer member variable and composition with a non-pointer variable. In English, we can read both relationships as a Car has-an Engine or a Car has-a Transmission. We can read the relationships in the opposite directions as "part of:" an Engine is part of a Car or a Transmission is part of a Car. Notice that it doesn't sound right in English (but the phrase may not work in other languages) to say that an Engine is-a Car or a Car is-an Engine, suggesting that the classes aren't naturally connected by inheritance.

Association is also a "has-a" relationship, but unlike composition and aggregation, it reads well in either direction: a contractor has-a project or a project has-a contractor. Although association is more general than the other constructive relationships, it's more difficult to implement and may not reflect the "real world" relationship between classes as well as composition or aggregation.

Contrasting Composition, Aggregation, and Association

Grouping three relationships and labeling them as "constructive" suggests they are similar in many ways. But if there isn't at least one difference, we wouldn't include three individually named relationships in our taxonomy. As you fill in the class relationship tables, look for the similarities and differences between these relationships.

Composition
Aggregation
Association

Modeling With Library Classes

In an often referenced 1976 Saturday Night Live sketch, Gilda Radner and Dan Aykroyd argue over "Shimmer." Is it a dessert topping or a floor wax? Chevy Chase settles the argument, explaining that it's both! (You can see how often people use the sketch to introduce concepts with a dual nature by Googling "dessert topping or floor wax.") We see the same conflict when we model problems using library or API classes, especially strings.

Three ways of modeling a Person with a string name. First, the Person class with a string attribute named 'name.' Second, Person and string are connected by composition. Finally, Person and string are connected by aggregation.
Modeling with library classes. Conceptually, strings are grouped sequences of characters. They are so elemental and necessary to computing that many programming languages implement them as fundamental or primitive data types, but others implement them as a class. So, when we model a program with UML class diagrams, how should we treat strings: as a fundamental type or a class?
  1. A string modeled as a fundamental data type - class Person has an attribute of string type.
  2. A string modeled as part of a whole with composition.
  3. A string modeled as part of a whole with aggregation.
How you model strings may depend on how they fit into a particular problem. The choice is yours if the problem doesn't suggest a specific implementation.