9.3 Class-Hierarchy Design
The design of a class hierarchy embodies a scheme for classifying a set of related classes according to a generalization-specialization principle. As shown in the figure below, there are three directions in the tree-structured hierarchy. Classes toward the top of the hierarchy (toward the root of the tree) are more generalized classes. The similarities among classes at one level are elevated to the classes at the next higher (more generalized) level. In the opposite direction, the classes descending from a given class are specializations of that class. Each specialization adds behavior and/or data that simultaneously makes the specialized class more specific, more capable, and less general. The specializing class is a refinement of the more general base class from which it is derived. The third direction in the hierarchy is across the classes that have the same immediate parent class. Each of these peer classes specializes the parent class in a different way, creating variety among the derived classes.
The role of the class hierarchy designer is not only to design the class hierarchy but also to create a rationalization of the class hierarchy. Rationalization in this sense means the creation of a logical, well reasoned (i.e., a rational) explanation for the organization of the hierarchy. The rationalization is concretely presented in the form of a logical condition that describes the refinement introduced by each specializing class. The logical conditions serve two purposes. First, the logical conditions identify the way in which the generalized (base) class is refined by the specialized (derived) class. Thus, the generalization-specialization direction in the class hierarchy is rationalized. Second, the difference between two peer classes can be understood by comparing their logical conditions. Through this comparison the variety (differentiation) direction in the class hierarchy is rationalized.
As an example of a rationalized class hierarchy, a small portion of Smalltalk's much more elaborate class hierarchy is shown in the figure below. In this portion of the class hierarchy, the universe of all Objects is divided into three classes: Boolean represents an object with unordered values, Magnitude represents individual objects that can be ordered with respect to each other, and Collection represents groups of objects as opposed to individual values. Individual ordered objects (i.e., the derived classes of Magnitude) are distinguished by the nature of the scale that determines how the objects are compared. The Char class has no scale; it is a simple predefined ordering of it elements. Individual objects of the Char class can be compared to each other but there is no sense of distance in the ordering. For example, the character A comes before the character B, but there is no sense that A is closer to or farther away from B than B is from C. The Number class is defined by a one-dimensional scale (such as for integers or floating-point numbers) where distance is an integral part of the nature of the values of this class. The Point class is defined by a two-dimensional scale, such as a Cartesian space or a computer screen. In contrast to ordered values are groups of objects represented by the Collection class. Two different collections are shown: Set and KeyedCollection. The rationalization for these two subclasses is that the objects of a KeyedCollection are indexed by the key value associated with each object, while the objects in a Set are unindexed. This rationalization of the class hierarchy makes it easier to understand the organization of the concepts in the hierarchy and guides where an extension should be made if new classes are added to the hierarchy.
There is a general strategy for finding a class hierarchy and its rationalization. The strategy has three steps:
These three steps are repeated iteratively until all the classes have been categorized, at which point there is a rationalization for the class hierarchy. It may be that not all of the classes can be placed into groups in the second step. These other classes can be considered again in a later iteration. The Flight Control Panel example below applies this general strategy in the design of a class hierarchy.
The rationalization of a class hierarchy is an important element
in object-oriented software design for several reasons. First
of all, it is a test of the adequacy of the class hierarchy. An
inability to define the logical conditions among classes is a
sign that the class hierarchy is not well founded. Additional
work or a different approach is needed to complete the rationalization.
The rationalization is a handy guide for locating a desired class
in the hierarchy. A (re)user needing a particular class can start
at the root of the hierarchy and ask which of the logical conditions
of its subclasses best describes the desired class. By iterating
through this process, either a suitable class will be found or
it will be clear that the class hierarchy does not contain a suitable
As the class hierarchy is extended, rationalization gives an indication of where further variety is possible. If the logical conditions attached to the classes derived from a given class are exhaustive, then additional variety is not possible because the existing derived classes have accounted for all possibilities. However, if this is not the case, then new subclasses can be introduced and the nature of these subclasses might be hinted at by what is left over by the existing conditions.
Designing and rationalizing the class hierarchy is an evolutionary
process. Hence, the class-hierarchy designer must approach the
task of identifying and classifying the common properties among
classes with the realization that: there may be more than one
good class hierarchy, so alternatives should be explored. Exploring
the design may involve backtracking to an earlier point and moving
forward again in a new direction. Alternative designs can be compared
on the basis of the clarity of their rationalization and the possibility
of further extension.
Creating a good class hierarchy is both a challenging and a rewarding task.
The principles of designing a class hierarchy are illustrated through the Flight Control Panel example described below. This panel is part of a larger flight simulator. Designing a good class hierarchy is important in this project because the Flight Control Panel may be modified during development, expanded in later version of the flight simulator, and components of the panel might be reused on other projects that have some of the same instrumentation.
The Flight Control Panel consists of different types of dials, gauges, and displays that provide the pilot with status information during the simulated flight. The panel is organized as shown in the figure below. The simulated aircraft has two engines and two fuel tanks. The left and right sides of the panel have a pair of instruments that show the engine speed and the fuel-tank level. The bottom center of the panel contains an altimeter and a clock.The two hands of the altimeter display the current altitude of the aircraft; one hand is calibrated in 1000-foot units and the other is calibrated in 100-foot units. The clock gives the elapsed time since takeoff in hours and minutes. The top center of the panel features a radar and a horizon/attitude display. The radar shows various icons and text representing other aircraft in the vicinity, while the horizon/attitude display's small centered icon represents the aircraft. This icon rotates about its center point to indicate the alignment of the aircraft's vertical axis to the ground. A horizontal line in this display indicates the alignment of the aircraft's horizontal axis with the ground. When the line is in the middle of the display, the aircraft is in level flight. The degree to which the line is toward the top or bottom of the display indicates how much the aircraft is descending or ascending.
An initial set of classes is easy to find in this problem. Each of the different types of instruments is a candidate for the definition of a class. These classes might be named:
The more difficult issue is how to organize these classes into a class hierarchy.
Several iterations of the a class hiearchy design for the Flight Control Panel are shown. Each iteration deepens the organization of the classes. The rationalization of the class hierarchy is developed at the same time as the hierarchy itself.
The first step in organizing the Flight Control Panel's classes is to identify any properties common to all of them. One evident property is that all of the elements are circular in shape. This property can be captured in a base class. All of the classes derived from this base class will inherit the property of being circular. There is no other evident property shared by all of the instruments. Therefore, groups of classes that share a new common property are sought. Some of the instruments convey information by a rotating hand; the classes representing these instruments are Speed, Altimeter, and Clock. These three classes can be organized into a sub-hierarchy whose base class is named Dial. The rationalization for the Dial class is "rotating hand". The class hierarchy at this point is shown in the figure below.
Following the general strategy, the immediate descendents of the Circle class, Radar, Dial, FuelGauge, and Horizon Attitude, are analyzed. Notice that this set of classes is a mixture of original classes (Radar, FuelGauge, Horizon Attitude) and a base class (Dial) created in the first iteration. A discriminating property among these four classes is that the Dial and FuelGauge classes display a single value or condition while the Radar and Horizon Attitude classes display multiple values or conditions. Using these groups as a guide, two new base classes may be invented: Indicator, a base class for single-value instruments, and Display, a base class for multiple-value instruments. The rationalizations for the Indicator and Display classes leads to a reconsideration of the name of the Circle class: the rationalization for the Indicator class would be read as "an Indicator is a single-value Circle," but use of the term Circle is inappropriate in this context. A more precise statement is, "an Indicator is a single-value Instrument that is shaped like a Circle." The name Instrument is more suggestive in this context and, thus, the name of the Circle class is changed to Instrument. The figure below shows the class hierarchy after the second iteration.
In this iteration, the classes derived from Indicator and those derived from Display are considered. Of the two classes derived from Indicator, Dial and FuelGauge, the rationalization "rotating hand" has already been developed for the Dial class. This leads naturally to finding the corresponding rationalization for the FuelGauge class. Instead of a rotating hand, the FuelGauge indicates its value with a horizontal line that moves up and down to show the level of the fuel in the tank. FuelGauge may therefore be described as a is as a sliding-position Indicator. In addition, neither of the two classes derived from Display, Radar and Horizon Attitude, has a rationalization. One essential difference between these two classes is that the Radar has a varying, unbounded number of items that it can display, while the Horizon Attitude class works with a fixed, bounded number of items. The rationalizations "varying number" and "fixed number" can be used for these classes. To check that this makes sense, the rationalization would indicate that "a Radar is an Instrument for a varying number of multiple values" and that "a Horizon Attitude is an Instrument for a fixed number of multiple values." Since these interpretations are consistent with the understanding of these classes, the rationalization is acceptable. The class hierarchy after the third iteration is shown below.
The fourth and final iteration reconsiders the classes derived from the Dial base class: Speed, Altimeter, and Clock. In searching for discriminating characteristics, it can be found that the Altimeter and the Clock have two rotating hands but the Speed indicator has only one. As there may be more specific kinds of indicators introduced in future versions of the system, it could be useful to make explicit this distinction. Therefore, a new base class, TwoHandDial, may be introduced as a class derived from Dial that becomes the class from which both Altimeter and Clock are derived. Clearly the rationalization for the TwoHandDial class would be "two hands," while the rationalization for the Speed class would be "one hand." To check that the accumulated rationalizations are sensible, the Clock class would be described as "an Instrument that displays a single value using two rotating hands" where the single value is understood to be the elapsed flight time. It is also sensible to describe the Speed class as "an Indicator that displays a single value using a single rotating hand." To complete the rationalization, the subclasses of TwoHandDial, Clock and Altimeter, should be considered. One essential difference between these two classes is that the Altimeter is bidirectional: its hands can move both clockwise and counterclockwise. The Clock, however, is unidirectional, as its hands can only move forward in the clockwise direction. If these properties are used for the rationalization of these two classes, the class hierarchy design is complete. The final class hierarchy is shown below.