10.4. Composition: Embedded Objects

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

Composition is a constructive relationship forming a tightly bound whole-part hierarchy. It achieves strong or tight binding by embedding or nesting the part objects inside the whole. This organization is a small step beyond the simple classes we created in the previous chapter. For example, consider the Time class that represents time as three variables: hours, minutes, and seconds. When a program instantiates the Time class, it creates an object with sufficient memory to store three integers, one each for the hours, minutes, and seconds. Ignoring some detail for a moment, we only need to change the "int" datatype to a class name to create a composition relationship.

class Time
{
	private:
		int	hours;
		int	minutes;
		int	seconds;
};
Time t;
 
 
 
 
 
 
A Time object with three embedded integers: hours, minutes, and seconds. When the program instantiates the Time class, the object has enough memory to contain the three integers - the integers are inside the object.
Class Specification Defining/instantiating An Object Abstract Representation
The Time class and object. We previously analogized the relationship between a class and an object as a cookie cutter and the cookies we make from it. The cookie cutter describes a cookie's size, shape, and decorations but is inedible. Alternatively, the cookies are the real treat that we eat. More formally, a class is a declaration and a type specifier. The object is a specialized variable created by a definition statement.
UML Classes Composition Classes Abstract Representation
A composition hierarchy. 'Car' is the whole class with two parts: 'Engin' and 'Transmission.' The composition symbol consists of a line with a solid or filled-in diamond at the end attached to the whole class (Car), and the plain end attached to the parts (Engine and Transmission).
class Engine
{
	. . .
};

class Transmission
{
	. . .
};

class Car
{
	private:
		Engine		cars_engine;
		Transmission	cars_transmission;
	. . .
};
A car object with two embedded objects: an engine and a Transmission. When a program creates a whole object (Car) with composed parts (Engine and Transmission), it creates instances of those classes and embeds them inside the whole object. Embedding makes the binding between a whole and its composed parts strong or tight.
Building a whole-part object with composition. In this example, a Car (the whole) consists of an Engine and a Transmission (the parts). We implement the whole-part relationship with two member variables (highlighted with blue and red) in the Car class. When a program instantiates the Car class, it simultaneously instantiates the Engine and Transmission classes and embeds the objects inside the Car. As composition is a whole-part relationship, we can say that "a Car has-an Engine" or that "a Transmission is part of a Car." However, nesting or embedding the parts inside the whole suggests that we can also read the relationship as "a Car contains an Engine" or "a Car contains a Transmission."

Although the Engine and Transmission details are not significant for this example, their class specifications must precede the Car specification. If we specify the classes in a single file, we must do so as illustrated here. Specifying the classes in separate header files requires the program to #include the part header files before specifying the whole. The next sections describe how to initialize and use part objects embedded in a whole object.

Composition Summary: Filling In The Table

Composition is a constructive relationship conveniently characterized by the "has-a" phrase. It has many property values in common with aggregation but differs in the strength or tightness of the binding between the objects. The following figure summarizes composition's property values. Use the summary to check and complete your entries in one of the blank Class Relationship Tables located at the end of the chapter.

  1. Semantics. We can read composition in either direction. We read it from the Whole to the Part as a has a relationship and from the Part to the Whole as a part of.
    • a Car has-an Engine
    • an Engine is part of a Car
    • a Car has-a Transmission
    • a Transmission is a part of a Car
  2. Directionality. Composition is a unidirectional or a one-way relationship. Unidirectionality means that
    A UML composition hierarchy with a whole class named Whole and a part class named Part. A composition connector, with the solid diamond attached to Whole, connects the two classes. An adjacent arrow points downwards, indicating composition's directionality: Whole to Part. The same UML composition hierarchy, but the arrow indicates the message passing direction: Whole to Part. The same UML composition hierarchy, but the arrow indicates knowledge: the Whole knows about the Part, but not the other direction. The same UML composition hierarchy, but the arrow indicates the direction of navigation: Whole to Part.
    (a)(b)(c)(d)
    1. The operations may only take place in one direction: from the whole to the part
    2. The whole object can send a message to the part object, which can respond to the message but cannot initiate message sending
    3. The whole "knows" about the part, but the part doesn't "know" about the whole
    4. It is possible to navigate from the whole to the part object but not from the part to the whole
  3. Binding Strength. The binding between the two objects is very strong or tight because the part object is embedded inside the whole object (Figure 2). The strength of the binding implies the final two characteristics:
    • Lifetime. The two objects have a coincidental lifetime, which means that the two objects are created and destroyed at the same time. It also means that the relationship between the two objects is permanent - it cannot be altered or broken.
    • Sharing. The binding between the two objects is so tight or strong that it forms an exclusive relationship - the whole object does not share its part object with any other object in the program.
  4. C++ implementation.
    class Car
    {
        private:
            Engine        my_engine;
            Transmission  my_transmission;
    };
Composition property values. Like all constructive relationships, C++ implements composition with class-scope (i.e., member) variables.