The generalization style of the module viewtype comes about when the is-a relation is specialized to generalization. This style comes in handy when an architect wants to support extension and evolution of architectures and individual elements. Modules in this style are defined in such a way that they capture commonalities and variations. When modules have a generalization relationship, the parent module is a more general version of the children modules. (Even though this style shares the terms parent and child with the decomposition style, they are used differently. In decomposition, a parent consists of its children. In generalization, parents and children have things in common.) The parent module owns the commonalities, and the variations are manifested in the children. Extensions can be made by adding, removing, or changing children; a change to the parent will automatically change all the children that inherit from it, which would support evolution.
Generalization implies inheritance of both interface and implementation. The child inherits structure, behavior, and constraints from its parent. Within an architectural description, the emphasis is on sharing and reusing interfaces and not so much on implementations.
2.3.2 Elements, Relations, and Properties
Table 2.3 summarizes the discussion of the characteristics of the generalization style. The element of the module generalization style is the module as defined by the module viewtype. We define a specialization of the is-a relation to be the generalization relation, whereby one module is a specialization of another module, and the second is a generalization of the first.
|Elements||Module, as defined by the module viewtype.|
|Relations||Generalization, which is the is-a relation as in the module viewtype.|
|Properties of elements||Besides the properties defined for a module in the module viewtype, a module can have the "abstract" property, which defines a module with interfaces but no implementation.|
|Properties of relations||The generalization relation can have a property that distinguishes between interface and implementation inheritance. If a module is defined as an abstract modulethe abstract propertyrestricting the generalization relation to implementation inheritance is not meaningful.|
A module can be an abstract module. Such a module defines its interfaces but does not have an implementation, at least not an implementation that is executable on its own. Child modules that comply with the parent's interface provide the necessary implementations.
In the transitive closure of the generalization relation, a module that inherits information is referred to as a descendant; the module providing the information is an ancestor. Cycles are not allowed. That is, a module can not be an ancestor or a descendant of itself.
The generalization relation can be used in several ways to implement various strategies. The fact that module A inherits from module B using interface inheritance is a promise that module A complies to at least the public interface from B. Module A may also inherit and use behavior implemented by module B, but this is not defined by this type of inheritance. This strategy is useful when variants of a module with different implementations are needed and one implementation of the module can substitute for another implementation with little or no effect on other modules.
Interface inheritance the definition of a new interface based on one or more previously defined interfaces. The new interface is usually a subset of the ancestors' interface(s).
With implementation inheritance, a module inherits behavior from its ancestors and modifies it to achieve its specialized behavior. The use of the generalization relation for implementation inheritance does not guarantee that the child module complies with the interfaces of the parent module; therefore, substitutability may be violated.
Implementation inheritance the definition of a new implementation based on one or more previously defined implementations. The new implementation is usually a modification of the ancestors' behavior.
2.3.3 What the Generalization Style Is For and What It's Not For
The generalization style can be used to support
2.3.4 Notations for the Generalization Style
Expressing generalization lies at the heart of UML. Modules are shown as classes, although they may also be shown as subsystems, as discussed in the decomposition style. Figure 2.5 shows the basic notation available in UML. Figure 2.6 shows how UML expresses interface and implementation inheritance. Figure 2.7 shows how UML represents multiple inheritance.
Figure 2.5. UML provides two line styles to show generalization. These two diagrams are semantically identical. UML allows an ellipsis ( . . . ) in place of a submodule, indicating that a module can have more children than shown and that additional ones are likely. Module Shape is the parent of modules Polygon, Circle, and Spline, each of which is in turn a subclass, child, or descendant of Shape. Shape is more general; its children are specialized versions. Therefore, the arrow points toward the more general entity.
Figure 2.6. UML shows interface and implementation inheritance in different ways. As this figure shows, the graphics must be enhanced with textual annotations to indicate whether it is the interface or implementation that is inherited. The graphical expression of UML is not powerful enough to differentiate. For example, in diagram (a) the generalization relation with properties shown on the left side usually means what is indicated on the right side; module A inherits the implementation of module B and realizes the same interface as module B. Whereas in diagram (b), generalization using interface inheritance indicated by the «interface» textual annotation usually means what is indicated on the right side: module A realizes the same interface as module B. Finally, in diagram (c), generalization using implementation inheritance indicated by the «implementation» textual annotation usually means module A inherits the implementation of module B but realizes its own interface.
Figure 2.7. Showing multiple inheritance graphically in UML is cumbersome. As with single interface and implementation inheritance, UML's graphical notation lacks expressive power to adequately describe what is inherited. So without additional textual annotations the graphic may be ambiguous. In this figure, module C is supposed to be a subclass/child/descendant of modules D and E, which means modules D and E are parents of module C.
2.3.5 Relation to Other Styles
Inheritance relationships complement the other module viewtype relations. For complex designs, it is useful to show inheritance relationships in a diagram separate from other types of relationships, such as decomposition.
COMING TO TERMS
Although typically associated with the generalization style, the notion of inheritance is also a useful technique for imposing organizational structure on other architectural elements. Inheritance relationships are used in descriptions of metamodels, styles, patterns, frameworks, or reference models more than in the description of a single system. Metamodels can be used to describe the element hierarchy in viewtypes or styles, for example. An element can be a module or a component, and a module can be a class or a layer. Accordingly, a class is-a module is-a element. Patterns, frameworks, and reference models describe a collection of elements and relations that appear again and again in the descriptions of various systems. Inheritance can be used in the architecture pattern itself. For example, examine the model-view-controller (MVC) pattern. This pattern has three pieces:
There are observer elements, between view and controller classes, that keep the user views up-to-date with changes in the model. View and controller elements may inherit from observer elements so they (view and controller) are notified of events of interest. The user of the MVC pattern may also use inheritance to specialize the elements of the particular application.
Viewed in this way, inheritance introduces the notions of architectural types and subtyping. The subtype relationship is used to evolve a given type to satisfy new requirements. This promotes off-the-shelf reuse and analysis through type checking and conformance.
UML refers to this organizing principle as generalization, making the distinction between generalization as a taxonomic relationship among elements and inheritance as a mechanism for combining shared incremental descriptions to form a full description of an element. Generalization implies inheritance of both interface and implementation. The child inherits structure, behavior, and constraints from its parent.
2.3.6 Examples of the Generalization Style
Figure 2.8 shows part of the module generalization view from the ECS system of Appendix A.
Figure 2.8. The primary presentation for part of an ECS module generalization view. The Ingest Data subsystem is shown as a class that is a generalization of a number of classes and provides a number of services.
Software Architectures and Documentation
Part I. Software Architecture Viewtypes and Styles
The Module Viewtype
Styles of the Module Viewtype
The Component-and-Connector Viewtype
Styles of the Component-and-Connector Viewtype
The Allocation Viewtype and Styles
Part II. Software Architecture Documentation in Practice
Documenting Software Interfaces
Choosing the Views
Building the Documentation Package
Other Views and Beyond
Rationale, Background, and Design Constraints