Abstract Classes

During the discussion of the mechanism of inheritance, it was mentioned that general classes stand at the top of the hierarchy. As we go up in the class hierarchy, classes become more and more general. In this context, some of the classes standing at the top of the hierarchy can play a specific role which is the role of defining some behavior that would be common to all other classes lower in the hierarchy. Such a class does not fully represent any object; it only represents a template for creating other objects that will have in common the behavior defined in this class. As such, these classes are abstract; there are no direct instances created from them. Abstract classes represent incomplete abstractions that can be useful for specifying contracts upon which concrete implementations will be based. These abstractions have a communicative role that allows designers to agree on interface specifications before starting concrete implementations. An abstract class is written with the expectation that its subclasses will add to its structure and behavior [BRJ99]. Part of designing an abstract class is specifying how this behavior will be used or refined by other classes lower in the hierarchy.

One of the classical examples of inheritance is taken from the domain of animals. At the top of the hierarchy a class named Mammals would be defined. According to The Pocket Oxford Dictionary, a mammal is "a warmblooded vertebrate of the class secreting milk to feed its young." The fact of feeding the young with milk is the most common thing that all animals have. It makes sense to create a class named Mammals that will capture this common behavior of all animals. However, there are no direct instances of the class Mammals, as mammal is a general concept representing a group of animals with common characteristics. Therefore, Mammals is an abstract class that has no instances and provides the most common data and behavior all animals have. Dog is a concrete animal that shares the characteristics described in Mammals. A Dog is a mammal and to represent a dog, a concrete class needs to be created inheriting from the abstract class Mammals. All other animal classes would inherit from the Mammals class. Each class representing a particular animal will extend the data and behavior defined at the abstract class level.

The UML presentation of an abstract class is the same as the one used for other classes, but the name of the class is in italicized font. Figure 4-21 shows an example of an abstract class.

Mammals %tge

ViultiplyO

Figure 4-21. Example of an abstract class. The name of the class is written in italics.

As previously mentioned, abstract classes do not have any instances. The attributes and the operations defined in an abstract class are inherited by all classes that are a specialization of the abstract class, meaning all classes that subclass the abstract class. Figure 4-17 shows an example of abstract classes created in a hierarchy of classes to address issues of developing a generic object-oriented plant simulator [AR97]. In this example, class Organ is an abstract class and its definition contains only attributes, no operations. In the same way, class Stem inherits from Organ but does not define any behavior either. Classes MainStem and BranchStem define additional attributes and the same behavior, such as potential_growth(), actual_growth(), and abscissionQ.

Let us look more carefully at this example of hierarchy as there are some important points to be made. When designing a class hierarchy, attention should be paid to the fact that every class of the hierarchy should have a well-defined purpose and role that will make the class have a specific place in the problem domain. Class's behavior is used in the dialog with other classes to achieve functionality. Classes should not be created just for being a placeholder of some values; they should play a specific and well-defined role in the domain in study. A class is a behavioral template for its instances [Zdo99].

A class without behavior generally causes difficulty of use and justification of need for such a class. Furthermore, inheriting from a class without behavior makes the problem even more complicated. As class Stem subclasses Organ, then Stem is a kind of Organ. Or class Organ does not have any defined behavior so stating that Stem is a kind of Organ does not provide additional information about class Stem. What is an Organ? What is the role of class Organ? How does class Organ dialog with other classes? Assigning a meaningful name to a class is not enough. A class should be the product of abstraction used to depict potential players in the domain under study. Selecting a meaningful name is important, as it enables other people to understand more easily the purpose and the role of the class, but a name is not sufficient. The name of the class by itself does not provide any behavior; it is only a label that distinguishes a class among others in the problem domain. Each class should provide some specific functionality that is not already defined in other classes.

What kind of behavior can class Organ provide? Class Organ should be provided with the most common behavior organs of a plant have. Organs grow or die, they actively interact with the surrounding environment. The role that organs play in collaborating with other organs or parts of the environment should be defined in class Organ in an abstract way. This behavior can be detailed or redefined by other classes inheriting from class Organ.

Furthermore, Figure 4-17 shows that both classes, MainStem and BranchStem, at the end of the hierarchy provide the same behavior (i.e., the ability to calculate potential and actual growth and abscission). Both classes inherit from class Stem, and Stem does not provide any behavior; it only adds two more attributes (length and number_leaves_on_stem) to the list of attributes defined at Organ class. Again, class MainStem inheriting from Stem is a kind of Stem. Stem does not provide any behavior nor does it inherit from Organ. Saying that a MainStem is a kind of Stem does not provide any information about what MainStem is or how it does behave.

In Figure 4-17, it is shown that MainStem and BranchStem are provided with behavior (operations actual_growth and potential_growth) that allows them to grow. A Stem is subject to potential and actual growth too; therefore, this behavior should be moved up to Stem level and each of the subclasses {MainStem and BranchStem) can provide polymorphic behavior for potential and actual growth, and abscission.

Abstract classes have a twofold role. The first role is a conceptual one; abstract classes can serve as modeling tools or specifications with the aim of identifying abstractions of the problem domain that will later be refined by concrete classes lower in the hierarchy. The second role is more of a utilitarian nature; abstract classes can serve as templates for improving reusability. The behavior defined at abstract classes will be implemented by concrete classes that subclass it [Tai96].

Abstract classes are a useful design technique that promotes code reuse. Depicting abstract classes in a problem domain is an iterative process that uses abstraction to find common functionalities in concrete classes and move it to a higher level in the hierarchy. The advantage of using abstract classes is that behavior common to many classes can be defined in only one place to be reused, modified, or improved later.

7. ABSTRACT CLASSES VERSUS INTERFACES

The concepts of abstract classes and interfaces are somewhat similar and one might be confused in deciding whether to use an interface or an abstract class. An abstract class defines a default behavior for some or all the operations that will be inherited by all the subclasses. The reuse of the behavior defined in an abstract class is realized through inheritance.

An interface does not define any default behavior at all. Interfaces only define specifications that will be implemented by classes realizing the interface. An interface may be implemented by many classes, and a class can implement many interfaces.

8. REALIZATION

A realization is a semantic relationship between classifiers in which one classifier specifies a contract that another classifier guarantees to carry out [BRJ99]. The most common use of the realization is between interfaces and the classifiers that agree to implement the interfaces. Figure 4-22 shows examples of realizations.

Figure 4-22. Examples of realizations.

Figure 4-22. Examples of realizations.

As shown in Figure 4-22, a realization is an agreement between a class and an interface. The interface defines the functionalities that the class should provide the implementation. The realization is presented by the line that connects the interface and the class. In the same way, a realization connects an interface that defines functionalities and the subsystem that would provide the implementation. Figure 4-23 shows another type of notation for realization.

Figure 4-23. Another notation for realization.

Figure 4-23. Another notation for realization.

0 0

Post a comment