In Chapter 7, you learned
how to create new types by declaring classes, and in Chapter 6, you saw a discussion of the
principle object relationships of association, aggregation, and
specialization . This chapter focuses on
specialization, which is implemented in C# through
inheritance . This chapter also explains how instances of more
specialized classes can be treated as if they were instances of more
general classes, a process known as polymorphism
. This chapter ends with a consideration of
sealed classes, which cannot be specialized, and a
discussion of the root of all classes, the Object
class.
Classes and their instances (objects) do not exist in a vacuum, but rather in a network of interdependencies and relationships, just as we, as social animals, live in a world of relationships and categories.
One of the most important relationships among objects in the real world is specialization, which can be described as the is-a relationship. When we say that a dog is a mammal, we mean that the dog is a specialized kind of mammal. It has all the characteristics of any mammal (it bears live young, nurses with milk, has hair), but it specializes these characteristics to the familiar characteristics of canis domesticus. A cat is also a mammal. As such, we expect it to share certain characteristics with the dog that are generalized in Mammal, but to differ in those characteristics that are specialized in cats.
The specialization and generalization relationships are both reciprocal and hierarchical. Specialization is just the other side of the generalization coin: Mammal generalizes what is common between dogs and cats, and dogs and cats specialize mammals to their own specific subtypes.
These relationships are hierarchical because they create a relationship tree, with specialized types branching off from more generalized types. As you move “up” the hierarchy, you achieve greater generalization. You move up toward Mammal to generalize that dogs, cats, and horses all bear live young. As you move “down” the hierarchy you specialize. Thus, the cat specializes Mammal in having claws (a characteristic) and purring (a behavior).
Similarly, when you say that ListBox
and Button
are Windows, you
indicate that there are characteristics and behaviors of Windows that
you expect to find in both of these types. In other words, Window
generalizes the shared characteristics of both ListBox
and Button
, while each specializes its own
particular characteristics and behaviors.
The Unified Modeling Language (UML) is a standardized language for describing an object-oriented system. The UML has many different visual representations, but in this case, all you need to know is that classes are represented as boxes. The name of the class appears at the top of the box, and (optionally) methods and members can be listed in the sections within the box.
In the UML, you model specialization relationships, as shown in
Figure 11-1. Note that
the arrow points from the more specialized class up to the more general
class. In the figure, the more specialized Button
and ListBox
classes point up to the more general
Window class.
It is not uncommon for two classes to share functionality. When
this occurs, you can factor out
these commonalities into a shared base class, which is more general than the
specialized classes. This provides you with greater reuse of common code
and gives you code that is easier to maintain, because the changes are
located in a single class rather than scattered among numerous
classes.
For example, suppose you started out creating a series of objects,
as illustrated in Figure
11-2. After working with RadioButtons, CheckBoxes, and Command
buttons for a while, you realize that they share certain characteristics
and behaviors that are more specialized than Window, but more general
than any of the three. You might factor these common traits and
behaviors into a common base class, Button
, and rearrange your inheritance
hierarchy, as shown in Figure
11-3. This is an example of how generalization is used in
object-oriented development.
The UML diagram in Figure 11-3 depicts the
relationship among the factored classes and shows that both ListBox
and Button
derive from Window, and that Button
is specialized into CheckBox and
Command. Finally, RadioButton derives from CheckBox. You can thus say
that RadioButton is a CheckBox, which in turn is a Button
, and that Button
s are Windows.
This is not the only, or even necessarily the best, organization for these objects , but it is a reasonable starting point for understanding how these types (classes) relate to one another.
Actually, although this discussion might reflect how some widget hierarchies are organized, I am very skeptical of any system in which the model does not reflect how I perceive reality, and when I find myself saying that a RadioButton is a CheckBox, I have to think long and hard about whether that makes sense. I suppose a RadioButton is a kind of CheckBox. It is a checkbox that supports the idiom of mutually exclusive choices. That said, it is a bit of a stretch and might be a sign of a shaky design.