Date: Sep 24, 2004 By Robert Martin.
Sample Chapter is provided courtesy of Prentice Hall PTR.
UML class diagrams allow us to denote the static contents of ? and the relationships between ? classes. In this chapter, Robert Martin explains the basics of UML class diagrams in a practical way.

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.



The Basics



Classes



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.



03fig01.gifFigure
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.



03fig02.gifFigure
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.



Association



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.



03fig03.gif
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.



03fig04.gifFigure 3.4




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."



Inheritance



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.



03fig05.gif
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.



03fig06.gifFigure
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.



03fig07.gifFigure
3.7
Lollipop interface Indicator.


An Example Class Diagram



Figure 3-8 shows a simple class diagram of part of an ATM system. This diagram is interesting both for what it shows, and for what it
does not show. Note that I have taken pains to mark all the interfaces. I consider it crucial to make sure my readers know
what classes I intend to be interfaces and which I intend to be implemented. For example, the diagram immediately tells you
that WithdrawalTransaction talks to a CashDispenser interface. Clearly some class in the system will have to implement the CashDispenser, but in this diagram we don't care which class it is.



03fig08.gifFigure
3.8
ATM class diagram.




Note that I have not been particularly thorough in documenting the methods of the various UI interfaces. Certainly WithdrawalUI will need more than just the two methods shown there. What about promptForAccount or informCashDispenserEmpty? Putting those methods in the diagram would just clutter it. By providing a representative batch of methods, I've given the
reader the idea. That's all that's really necessary.



Again note the convention of horizontal association and vertical inheritance. This really helps to differentiate these vastly
different kinds of relationships. Without a convention like this it can be hard to tease the meaning out of the tangle.



Notice how I've separated the diagram into three distinct zones. The transactions and their actions are on the left, the various
UI interfaces are all on the right, and the UI implementation is on the bottom. Note also that the connections between the
grouping are minimal and regular. In one case it is three associations, all pointing the same way. In the other case it is
three inheritance relationships all merged into a single line. The grouping, and the way they are connected help the reader
to see the diagram in coherent pieces.



You should be able to see the code as you look at the diagram. Is Listing 3-1 close to what you expected for the implementation of UI?



Example 3-1. UI.java




public class UI implements
WithdrawalUI, DepositUI, TransferUI
{
private Screen itsScreen;
private MessageLog itsMessageLog;

public void displayMessage(String message)
{
itsMessageLog.logMessage(message);
itsScreen.displayMessage(message);
}
}

The Details



There are a vast number of details and adornments that can be added to UML class diagrams. Most of the time these details
and adornments should not be added. But there are times when they can be helpful.



Class stereotypes



Class stereotypes appear between guillemet3 characters, usually above the name of the class. We have seen them before. The ≪interface≫ denotation in Figure 3-8 is a class stereotype. ≪interface≫ is one of two standard stereotypes that can be used by Java programmers. The other is
≪utility≫.



≪interface≫



All the methods of classes marked with this stereotype are abstract. None of the methods can be implemented. Moreover, ≪interface≫
classes can have no instance variables. The only variables they can have are static variables. This corresponds exactly to
Java interfaces. See Figure 3-9.



03fig09.gifFigure
3.9
≪interface≫ class stereotype.




I draw interfaces so often that spelling the whole stereotype out at the white board can be pretty inconvenient. So I often
use the shorthand in the lower part of Figure 3-9 to make the drawing easier. It's not standard UML, but it's much more convenient.



≪utility≫



All the methods and variables of a ≪utility≫ class are static. Booch4 used to call these class utilities. See Figure 3-10.



03fig10.gifFigure
3.10
≪utility≫ class stereotype.




You can make your own stereotypes if you like. I often use stereotypes like ≪persistent≫, ≪C-API≫, ≪struct≫, or ≪function≫.
You just have to make sure that the people who are reading your diagrams know what your stereotype means.



Abstract classes



In UML there are two ways to denote that a class or a method is abstract. You can write the name in italics, or you can use
the {abstract} property. Both options are shown in Figure 3-11.



03fig11.gifFigure
3.11
Abstract classes.




It's a little difficult to write italics at a white board, and the {abstract} property is wordy. So at the white board, if
I need to denote a class or method as abstract, I use the convention shown in Figure 3-12. Again, this isn't standard UML, but at the white board it is a lot more convenient.5



03fig12.gifFigure
3.12
Unofficial denotation of abstract classes.




Properties



Properties, like {abstract} can be added to any class. They represent extra information that's not usually part of a class.
You can create your own properties at any time.



Properties are written in a comma separated list of name?value pairs, like this:



{author=Martin, date=20020429, file=shape.java, private}

The properties in the preceding example are not part of UML. The {abstract} property is the only defined property of UML that
Java programmers would find useful.



If a property does not have a value, it is assumed to take the boolean value true. Thus, {abstract} and {abstract = true} are synonyms.



Properties are written below and to the right of the name of the class, as shown in Figure 3-13.



03fig13.gif Figure 3.13 Properties.



Other than the {abstract} property, I don't know when you'd this useful. Personally, in the many years that I've been writing
UML diagrams, I've never had occasion to use class properties for anything.



Aggregation



Aggregation is a special form of association that connotes a "whole/part" relationship. Figure 3-14 shows how it is drawn and implemented. Notice that the implementation shown in Figure 3-14 is indistinguishable from association. That's a hint.



03fig14.gif
Figure 3.14
Aggregation.




Unfortunately, UML does not provide a strong definition for this relationship. This leads to confusion because various programmers
and analysts adopt their own pet definitions for the relationship. For that reason I don't use the relationship at all, and
I recommend that you avoid it as well. In fact, this relationship has been dropped from UML 2.0.



The one hard rule that UML gives us regarding aggregations is simply this: A whole cannot be its own part. Therefore instances cannot form cycles of aggregations. A single object cannot be an aggregate of itself, two objects cannot be aggregates of
each other, three objects cannot form a ring of aggregation, and so on. See Figure 3-15



03fig15.gifFigure
3.15
Illegal cycles of aggregation between instances.




I don't find this to be a particularly useful definition. How often am I concerned about making sure that instances form a
directed acyclic graph? Not very often. Therefore I find this relationship useless in the kinds of diagrams I draw.



Composition



Composition is a special form of aggregation, as shown in Figure 3-16. Again, notice that the implementation is indistinguishable from association. However, this time the reason is not due to
a lack of definition; this time it's because the relationship does not have a lot of use in a Java program. C++ programmers,
on the other hand, find a lot of use for it.



03fig16.gif Figure 3.16 Composition.



The same rule applies to composition that applied to aggregation. There can be no cycles of instances. An owner cannot be
its own ward. However, UML provides quite a bit more definition.





  • An instance of a ward cannot be owned simultaneously by two owners. The
    object diagram in Figure
    3-17
    is illegal. Note, however, that the corresponding class diagram
    is not illegal. An owner can transfer ownership of a ward to another owner.


    03fig17.gifFigure
    3.17
    Illegal composition.





  • The owner is responsible for the lifetime of the ward. If the owner is
    destroyed, the ward must be destroyed with it. If the owner is copied, the
    ward must be copied with it.





In Java destruction happens behind the scenes by the garbage collector, so there is seldom a need to manage the lifetime of
an object. Deep copies are not unheard of, but the need to show deep copy semantics on a diagram is rare. So, though I have
used composition relationships to describe some Java programs, such use is infrequent.



Figure 3-18 shows how composition is used to denote deep copy. We have a class named Address that holds many Strings. Each string holds one line of the address. Clearly, when you make a copy of the Address, you want the copy to change independently of the original. Thus, we need to make a deep copy. The composition relationship
between the Address and the Strings indicates that copies need to be deep.6



03fig18.gifFigure
3.18
Deep copy is implied by composition.




Multiplicity



Objects can hold arrays or vectors of other objects, or they can hold many of the same kind of objects in separate instance
variables. In UML this can be shown by placing a multiplicity expression on the far end of the association. Multiplicity expressions can be simple numbers, ranges, or a combination of
both. For example, Figure 3-19 shows a BinaryTreeNode, using a multiplicity of 2.



03fig19.gifFigure
3.19
Simple multiplicity.




Here are the allowable forms:
































? Digit.



The exact number of elements.



? * or 0..*



Zero to many.



? 0..1



Zero or one. In Java this is often implemented with a reference that can be null.



? 1..*



One to many.



? 3..5



Three to five.



? 0, 2..5, 9..*



Silly, but legal.




Association stereotypes



Associations can be labeled with stereotypes that change their meaning. Figure 3-20 shows the ones that I use most often.



03fig20.gifFigure
3.20
Association stereotypes.




The ≪create≫ stereotype indicates that the target of the association is created by the source. The implication is that the source creates
the target and then passes it around to other parts of the system. In the example I've shown a typical factory.



The ≪local≫ stereotype is used when the source class creates an instance of the target and holds it in a local variable. The implication
is that the created instance does not survive the member function that creates it. Thus, it is not held by any instance variable
nor passed around the system in any way.



The ≪parameter≫ stereotype shows that the source class gains access to the target instance though the parameter of one of its member functions.
Again, the implication is that the source forgets all about this object once the member function returns. The target is not
saved in an instance variable.



Using dashed dependency arrows, as the diagram shows, is a common and convenient idiom for denoting parameters. I usually
prefer it to using the ≪parameter≫ stereotype.



The ≪delegate≫ stereotype is used when the source class forwards a member function invocation to the target. There are a number of design
patterns where this technique is applied, such as PROXY, DECORATOR, and COMPOSITE7 . Since I use these patterns a lot, I find the notation helpful.



Inner classes



Inner (nested) classes are represented in UML with an association adorned with a crossed circle, as shown in Figure 3-21.



03fig21.gifFigure
3.21
Inner class.




Anonymous inner classes



One of Java's more interesting features is anonymous inner classes. While UML does not have an official stance on these, I
find the notation in Figure 3-22 works well for me. It is concise and descriptive. The anonymous inner class is shown as a nested class that is given the
≪anonymous≫ stereotype, and is also given the name of the interface it implements.



03fig22.gifFigure
3.22
Anonymous inner class.




Association classes



Associations with multiplicity tell us that the source is connected to many instances of the target, but the diagram doesn't
tell us what kind of container class is used. This can be depicted by using an association class, as shown in Figure 3-23.



03fig23.gifFigure
3.23
Association class.




Association classes show how a particular association is implemented. On the diagram they appear as a normal class connected
to the association with a dashed line. As Java programmers we interpret this to mean that the source class really contains
a reference to the association class, which in turn contains references to the target.



Association classes can also be used to indicate special forms of references, such as weak, soft, or phantom references. See
Figure 3-24. On the other hand, this notation is a bit cumbersome and is probably better done with stereotypes as in Figure 3-25.



03fig24.gifFigure
3.24
Association class denoting a weak reference.




03fig25.gifFigure
3.25
Stereotype denoting a weak reference.




Association qualifiers



Association qualifiers are used when the association is implemented through some kind of key or token, instead of with a normal
Java reference. The example in Figure 3-26 shows a LoginServlet associated with an Employee. The association is mediated by a member variable named empid, which contains the database key for the Employee.



03fig26.gifFigure
3.26
Association qualifier.




I find this notation useful in rare situations. Sometimes it's convenient to show that an object is associated to another
through a database or dictionary key. It is important, however, that all the parties reading the diagram know how the qualifier
is used to access the actual object. This is not something that's immediately evident from the notation.

Conclusion



There are lots of widgets, adornments, and whatchamajiggers in UML. There are so many that you can spend a long time becoming
an UML language lawyer, enabling you to do what all lawyers can ? write documents nobody else can understand.



In this chapter I have avoided most of the arcana and byzantine features of UML. Rather I have showed you the parts of UML
that I use. I hope that along with that knowledge I have instilled within you the values of minimalism. Using too little of UML
is almost always better than using too much.

Notes



[Booch1994]: Grady Booch, Object Oriented Analysis and Design with Applications. Redwood City, CA.: Benjamin Cummings, 1994.



[Gamma1995]: Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. Design Patterns. Reading, Mass.: Addison-Wesley, 1995.



Posted by 아름프로
BLOG main image

카테고리

분류 전체보기 (539)
이야기방 (19)
토론/정보/사설 (16)
IBM Rational (9)
U-IT (0)
SOA/WS/ebXML (110)
개발방법론/모델링 (122)
J2SE (34)
J2EE (60)
DataBase (39)
Open Projects (30)
BP/표준화 (50)
Apache Projects (15)
Web/보안/OS (22)
Tools (7)
AJAX/WEB2.0 (1)
Linux/Unix (1)
영어 (0)
비공개방 (0)

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

달력

«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28

글 보관함

Total :
Today : Yesterday :