The UML Profile for Framework Architectures

2.2 Class diagrams

Class diagrams are the most important notation for object modeling. A class diagram serves several important purposes:

Figure 2.1 shows a sample UML class diagram that contains all the elements provided by the UML standard. The diagram consists of six classes (namely Human, Child, Employee, House, Roof, and Door) and two interfaces (Mammal and Thing). The interfaces are presented in different shapes. Thing is drawn as a class with the so-called stereotype interface on it, whereas Mammal is drawn as a small circle without any indication of an interface method.

Figure 2.1. A sample class diagram

Class House implements the Thing interface. Classes Child and Employee are subclasses of Human a generalization relation is shown in the form of an unfilled triangular arrowhead. Generalization is a relationship between a subclass and a superclass. Compared to Java, where a subclass may have only one direct superclass, the UML standard allows classes to inherit from as many superclasses as desired. In Java, however, each class may implement an arbitrary number of interfaces. This is sufficient to allow general type hierarchies, but avoids technical involvement when inheriting the same attribute or method several times along different paths.

Furthermore, the implementation relationship between classes and interfaces and the generalization relation between classes are quite similar. Both are therefore visualized in the same way through triangles with a solid line.[4] An abstract class is drawn with a class name in italics, such as class Human.

[4] The UML standard 1.4 proposes the use of a dashed line for interface implementation, but that distinction from inheritance is not necessary because it is clear already from the context of the line. We suggest this simplification in UML-F to show that, from a conceptual viewpoint, interfaces and classes are just variants of each other (with different restrictions on their capability).

The unnamed association between the classes Human and House represents ownership. It has one role and two multiplicity identifiers attached to it. The role name 'owner' can be used to navigate from an object of class House to the corresponding Human object (its owner). A solid arrow shows the navigability of the association in this direction. Multiplicity 1 describes that there is exactly one such object. Note that associations may have quite a number of different realizations, but in many cases it is a good choice to use an attribute[5] as the implementation choice. Multiplicity * in the other direction indicates that many objects of class House may belong to one Human object. However, as there is no arrow associated with it, it is unclear whether navigation in the direction described is possible.[6]

[5] 'Attribute' is the UML jargon for instance variable. In this book, both are used synonymously.

[6] We will later develop a concept that allows us to distinguish between the lack of information (e.g. through omission) and the explicit decision to not have the navigation available. This concept is generalized for many circumstances and nicely extends the UML standard.

Classes and interfaces do have signatures. An interface signature consists of methods, while a class signature consists of methods and attributes. Each method is described through its name, argument types, and return type. An attribute signature consists of name and type. The UML calls the methods operations we use the terms 'method' and 'operation' interchangeably in the rest of this book.[7]

[7] In general, the concept of operations embraces the notion of method implementation. In particular, operations identified in early development phases don't necessarily become methods in the implementation stage.

The class diagram in Figure 2.1 omits method and attribute signature lists for most classes; only the classes Human and Employee, and the interface Thing carry a signature. As class Employee inherits from class Human, it automatically inherits its signature, which it extends by the newly defined attribute salary and method acceptNewJob(). In an analogous way, class House inherits the signature of interface Thing and therefore has to provide an implementation of method getHeight(). Abstract methods are denoted in italics, as exemplified by celebrateBirthday() in class Human.

House objects are composed of objects of classes Roof and Door. Each House object consists of exactly one Roof object (multiplicity 1) and an unspecified number of Door objects (multiplicity *). There are a number of different flavors of object composition. A weak form, namely aggregation, is represented through an unfilled diamond.[8] Aggregation has a number of different interpretations, with some of them almost identical to normal associations. Thus, one recommendation is not to use this weak form at all. The strong form, namely composition (represented by a black diamond), is characterized by coincident lifetimes and unshared composed objects. This means that the composed elements do not live longer than the composition itself, and that each composed element belongs to, at most, one composition. In this example, it means that whenever a house is destroyed, the corresponding roof and doors must also be destroyed, and that each door and roof belong only to one house. For a detailed discussion, we refer to Henderson-Sellers and Barbier (1999).

[8] Unfilled diamonds, and therefore aggregation, are not shown or used anywhere in this book. Unfilled diamonds are also called 'white' diamonds. By analogy, 'black' diamonds are the same as filled diamonds.

Attributes and methods are given in two compartments within a class rectangle. Figure 2.2 shows how to represent these elements together with their visibility. Visibility marker '+' denotes public attributes or methods. It corresponds to Java's public language construct, allowing access from any other object. Private access is marked by '-'. It corresponds to Java's 'private' language construct, allowing access only within the scope of that object. Finally, visibility marker '#' expresses that a class and its subclasses may access this element. In C++ this is called 'protected', whereas in Java the same concept was originally called 'private protected'.[9]

[9] Java no longer supports the accessibility modifier 'private protected'. Java's protected accessibility modifier is about as close as you can get, but it is not quite the same since it allows classes in the same package to access the attribute or method, whether or not they are subclasses. Thus, we recommend clarification of the meaning of '#' for each specific project, or its omission from use altogether. The UML standard does not fully determine its meaning.

Figure 2.2. The notational elements of a class

Figure 2.2 also contains a comment in a rectangle with a dog's ear. Comments can contain informal explanations (such as the one above), pseudocode, such as age+=1, or properties specified in the Object Constraint Language (OCL), such as age=age@pre+1. OCL is part of the UML standard. It is a textual supplement that allows formal specification of conditions. For a complete description of OCL, we refer to Warmer and Kleppe (1999).

Категории