Making Generalizations in UML 2
It’s natural to classify objects in categories and to organize categories into subcategories. If you look for a place to live, you find yourself categorizing a dwelling unit as a house, apartment, townhouse, condominium, mansion, and so on. Houses can, in turn, be further organized by styles such as ranch, split-level, colonial, and saltbox. UML provides you with notation to capture these types of classifications — also known as generalization and specialization — and make use of them as a modeler and a programmer.
Some object-oriented developers will go to great lengths to save a little work. When they can model something once and reuse it, they’re interested. If they can write a method (the program code for an operation) for a class only once and use it many times, then sign them up for higher productivity. If you want to save yourself time by specifying attributes and operations once and then reusing them many times, read on.
As you define classes, you may notice that some classes have the same attributes or the same operations. When this is the case, you place these common features (attributes, operations, and so on) in a more generic class called the superclass. The classes that share the common features are known as subclasses of the superclass. For example, the length of recorded material on a videotape, audiotape, compact disc, or movie film is an attribute of all four kindsof recorded media. These classes can share other attributes as well, such as their physical dimensions and the date each one was used to make a recording. In this case the superclass would be RecordedMedia, the subclasses would be Videotape, Audiotape, CompactDisc, and MovieFilm, and some shared attributes could include recordedLength and totalLength.
This process of finding similar attributes or operations across classes is known as generalization. For example you generalize the attribute recordLength into a more generic class called RecordedMedia. The process for showing a generalization in UML is simple:
1. Identify the subclasses.
Locate classes that have the same attributes and/or operations. These classes are your subclasses.
2. Create a superclass.
Provide a superclass to hold the common attributes and/or operations of the subclasses. Give the superclass a name that categorizes all the subclasses. Placing the superclass above the subclasses in the diagram make it easier to read but is not required.)
3. Add common features to the superclass.
Remove the common attributes and operations from the subclasses and place them (once) in the superclass.
4. Draw a generalization relationship.
You draw a generalization line from each subclass to the superclass. In UML the generalization line is represented as a solid line with a hollow arrowhead at the superclass end. In UML, a line with the hollow arrowhead that connects a subclass to a superclass is known as a generalization relationship.
After you create a superclass with the common features such as attributes and operations, the subclasses inherit those features from the superclass. This way you only have to write the common features once in the superclass instead of many times in each of the subclasses.
You can tell whether you have a generalization by looking at the language you (or others) use to describe the relationship between classes. Notice that in describing recorded media and its various types such as videotape earlier in this section, the phrase “four kindsof recorded media” appeared. If you find yourself using phrases such as “kind of” or “type of,” then chances are you have a generalization on your hands.
Say that one of your clients is concerned with keeping track of materials in an archive. This client has accumulated different kinds of recorded media such as videotapes and audiotapes. As modelers, you need to capture the differences between these media as well as their similarities. The diagram in Figure 1 shows the beginnings of several generalizations, arranged in an inheritance hierarchy.
Developers use the term generalization or inheritance to refer to the same concept of reusing shared attributes and operations that you show in a superclass and reuse in subclasses. Generalization refers to the concept of generalizing from specifics (the subclasses) to the generic (the superclass). Inheritance refers to the effect of generalization on the subclasses.
When you see a generalization relationship between classes, its meaning is very different from that of an association relationship between classes. An association is ultimately a relationship among many objects — some instances of one class have a relationship (link) with instances of the other class. In a generalization relationship among classes, the relationship is really about the classes. The best you can say is that an object created from a subclass contains all the features of the subclass and of the superclass.
You only have one object from a class in a generalization relationship. Even though you show two classes, the subclass and the superclass, you only have one object that gets created. You can think of an object of the Videotape class also being an object of the RecordedMedia class because of inheritance. Figure 2 shows an object created from the Videotape class with all its attributes. (The instance of a class is represented as an object symbol.) You don’t have two different objects (one for RecordedMedia and one for Videotape), just one object. When the object vtu83-1023 was created, all its attributes’ values were set. The recording on the tape is 57 minutes. The total length of the physical tape is 60 minutes. The tape is a Umatic videocassette with a height of 10 inches, a width of 7 inches, and a depth of 1.5 inches. The recording is analog, and a log of tape contents is attached to the tape for the archivist to reference.
You only have one instance defined by a subclass and its superclass. The subclass and the superclass may have a constructor operation (to create the instance) and a destructor operation (to destroy the instance). When your software runs, and you create an instance of a subclass, the constructor of the superclass is executed first, followed by the constructor of the subclass. When it comes time to eliminate the instance you created, the destructor of the subclass is called first, followed by the destructor of the superclass. If things are more complex because you have subclasses of subclasses, just remember: Constructors are invoked from the top of the inheritance hierarchy to the bottom; destructors are called in order from the lowest subclass up to the highest superclass.