UML class diagrams allow us to denote the static contents of and the relationships between classes. In a class diagram we can show the member variables, and member functions of a class. We can also show whether one class inherits from another, or whether it holds a reference to another. In short, we can depict all the source code dependencies between classes.
This can be valuable. It can be much easier to evaluate the dependency structure of a system from a diagram than from source code. Diagrams make certain dependency structures visible. We can see dependency cycles, and determine how best to break them. We can see when abstract classes depend upon concrete classes, and determine a strategy for rerouting such dependencies.
Figure 3-1 shows the simplest form of class diagram. The class named Dialer is represented as a simple rectangle. This diagram represents nothing more than the code shown to its right.
Figure 3.1 Class icon.
This is the most common way you will represent a class. The classes on most diagrams don't need any more than their name to make clear what is going on.
A class icon can be subdivided into compartments. The top compartment is for the name of the class, the second is for the variables of the class, and the third is for the methods of the class. Figure 3-2 shows these compartments and how they translate into code.
Figure 3.2 Class icon compartments with corresponding code.
Notice the character in front of the variables and functions in the class icon. A dash () denotes private, a hash (#) denotes protected, and a plus (+) denotes public.
The type of a variable, or a function argument is shown after the colon following the variable or argument name. Similarly, the return value of a function is shown after the colon following the function.
This kind of detail is sometimes useful, but should not be used very often. UML diagrams are not the place to declare variables and functions. Such declarations are better done in source code. Use these adornments only when they are essential to the purpose of the diagram.
Associations between classes most often represent instance variables that hold references to other objects. For example, in Figure 3-3 we see an association between Phone and Button. The direction of the arrow tells us that Phone holds a reference to Button. The name near the arrowhead is the name of the instance variable. The number near the arrowhead tells us how many references are held.
Figure 3.3 Association.
In Figure 3-3 we saw that 15 Button objects were connected to the Phone object. In Figure 3-4, we see what happens when there is no limit. A Phonebook is connected to many PhoneNumber objects. The star means many. In Java this is most commonly implemented with a Vector, a List, or some other container type.
You may have noticed that I avoided using the word "has". I could have said: "A Phonebook has many PhoneNumbers." This was intentional. The common OO verbs HASA and ISA have lead to a number of unfortunate misunderstandings. We'll explore some of them later in Chapter 6. For now, don't expect me to use the common terms. Rather, I'll use terms that are descriptive of what actually happens in software, such as: "is connected to."
You have to be very careful with your arrowheads in UML. Figure 3-5 shows why. The little arrowhead pointing at Employee denotes inheritance1. If you draw your arrowheads carelessly, it may be hard to tell whether you mean inheritance or association. To make it clearer, I often make inheritance relationships vertical and associations horizontal.
Figure 3.5 Inheritance.
In UML all arrowheads point in the direction of source code dependency. Since it is the SalariedEmployee class that mentions the name of Employee, the arrowhead points at Employee. So, in UML, inheritance arrows point at the base class.
UML has a special notation for the kind of inheritance used between a Java class and a Java interface. It is shown, in Figure 3-6, as a dashed inheritance arrow2. In the diagrams to come, you'll probably catch me forgetting to dash the arrows that point to interfaces. I suggest you forget to dash the arrows that you draw on white boards too. Life's too short to be dashing arrows.
Figure 3.6 Realizes relationship.
Figure 3-7 shows another way to convey the same information. Interfaces can be drawn as little lollipops on the classes that implement them. We often see this kind of notation in COM designs.
Figure 3.7 Lollipop interface Indicator.