In contrast to communication diagrams, in sequence diagrams the lifeline boxes include a vertical line extending below themthese are the actual lifelines. Although virtually all UML examples show the lifeline as dashed (because of UML 1 influence), in fact the UML 2 specification says it may be solid
or dashed.
Each (typical synchronous) message between objects is represented with a message expression on a
filled-arrowed [3] solid line between the vertical lifelines (see Figure 15.7). The time ordering is organized from top to bottom of lifelines.
[3] An open message arrow means an asynchronous message in an interaction diagram.
In the example of Figure 15.7 the starting message is called a
found message in the UML, shown with an opening solid ball; it implies the sender will not be specified, is not known, or that the message is coming from a random source. However, by convention a team or tool may ignore showing this, and instead use a regular message line without the ball, intending by convention it is a found message.[4]
[4] Therefore, many of the book examples won't bother with the found message notation.
As illustrated in Figure 15.7, sequence diagrams may also show the focus of control (informally, in a regular blocking call, the operation is on the call stack) using an
execution specification bar (previously called an
activation bar or simply an
activation in UML 1). The bar is optional.
Guideline : Drawing the bar is more common (and often automatic) when using a UML CASE tool, and less common when wall sketching.
There are two ways to show the return result from a message:
Using the message syntax
returnVar = message(parameter) .
Using a reply (or return) message line at the end of an activation bar.
Both are common in practice. I prefer the first approach when sketching, as it's less effort. If the reply line is used, the line is normally labelled with an arbitrary description of the returning value. See Figure 15.8.
You can show a message being sent from an object to itself by using a nested activation bar (see Figure 15.9).
Object creation notation is shown in Figure 15.10. Note the UML-mandated
dashed line.[5] The arrow is filled if it's a regular synchronous message (such as implying invoking a Java constructor), or open (stick arrow) if an asynchronous call. The message name
create is not requiredanything is legalbut it's a UML idiom.
[5] I see no value in requiring a
dashed line, but it's in the spec… Many author examples use a solid line, as early draft versions of the spec did as well.
The typical interpretation (in languages such as Java or C#) of a
create message on a dashed line with a filled arrow is "invoke the
new operator and call the constructor".
In some circumstances it is desirable to show explicit destruction of an object. For example, when using C++ which does not have automatic garbage collection, or when you want to especially indicate an object is no longer usable (such as a closed database connection). The UML lifeline notation provides a way to express this destruction (see Figure 15.11).
To support conditional and looping constructs (among many other things), the UML uses
frames .[6] Frames are regions or fragments of the diagrams; they have an operator or label (such as
loop ) and a guard[7] (conditional clause). See Figure 15.12.
[6] Also called diagram frames or interaction frames.
[7] The
[boolean test] guard should be placed
over the lifeline to which it belongs.
The following table summarizes some common frame operators:
Frame Operator | Meaning |
---|---|
alt | Alternative fragment for mutual exclusion conditional logic expressed in the guards. |
loop | Loop fragment while guard is true. Can also write loop(n) to indicate looping n times. There is discussion that the specification will be enhanced to define a FOR loop, such as loop(i, 1, 10) |
opt | Optional fragment that executes if guard is true. |
par | Parallel fragments that execute in parallel. |
region | Critical region within which only one thread can run. |
The LOOP frame notation to show looping is shown in Figure 15.12.
An OPT frame is placed around one or more messages. Notice that the guard is placed
over the related lifeline. See Figure 15.13.
The UML 2.x notation to show a single conditional message is heavyweight, requiring an entire OPT frame box around one message (see Figure 15.13). The older UML 1.x notation for
single conditional messages in sequence diagrams is not legal in UML 2, but so simple that especially when sketching it will probably be popular for years to come. See Figure 15.14.
Guideline : Use UML 1 style only for simple single messages when sketching.
An ALT frame is placed around the mutually exclusive alternatives. See Figure 15.15.
A common algorithm is to iterate over all members of a collection (such as a list or map), sending the same message to each. Often, some kind of iterator object is ultimately used, such as an implementation of
java.util.Iterator or a C++ standard library iterator, although in the sequence diagram that low-level "mechanism" need not be shown in the interest of brevity or abstraction.
At the time of this writing, the UML specification did not (and may never) have an official idiom for this case. Two alternatives are shownreviewed with the leader of the UML 2 interaction specificationin Figure 15.16 and Figure 15.17.
Note the
selector expression
lineItems[i] in the lifeline of Figure 15.16. The selector expression is used to select one object from a group. Lifeline participants should represent one object, not a collection.
In Java, for example, the following code listing is a possible implementation that maps the explicit use of the incrementing variable
i in Figure 15.16 to an idiomatic solution in Java, using its enhanced
for statement (C# has the same).
public class Sale
{
private List<SalesLineItem> lineItems =
new ArrayList<SalesLineItem>();
public Money getTotal()
{
Money total = new Money();
Money subtotal = null;
for ( SalesLineItem lineItem : lineItems )
{
subtotal = lineItem.getSubtotal();
total.add( subtotal );
}
return total;
}
// …
}
Another variation is shown in Figure 15.17; the intent is the same, but details are excluded. A team or tool could agree on this simple style by convention to imply iteration over all the collection elements.[8]
[8] I use this style later in the book.
Frames can be nested. See Figure 15.18.
Figure 15.19 illustrates probably better than words. An
interaction occurrence (also called an
interaction use ) is a reference to an interaction within another interaction. It is useful, for example, when you want to simplify a diagram and factor out a portion into another diagram, or there is a reusable interaction occurrence. UML tools take advantage of them, because of their usefulness in relating and linking diagrams.
sd and
ref frames.
They are created with two related frames:
a frame around an entire sequence diagram[9] , labeled with the tag
sd and a name, such as
[9] Interaction occurrences and
ref frames can also be used for
communication diagrams.
a frame tagged
ref , called a
reference , that refers to another named sequence diagram; it is the actual interaction occurrence
Interaction overview diagrams also contain a set of reference frames (interaction occurrences). These diagrams organized references into a larger structure of logic and process flow.
Guideline : Any sequence diagram can be surrounded with an
sd frame, to name it. Frame and name one when you want to refer to it using a
ref frame.
You can show class or static method calls by using a lifeline box label that indicates the receiving object is a class, or more precisely, an
instance of a
metaclass (see Figure 15.20).
What do I mean? For example, in Java and Smalltalk, all classes are conceptually or literally
instances of class
Class ; in .NET classes are instances of class
Type . The classes
Class and
Type are
metaclasses , which means their instances are themselves classes. A specific class, such as class
Calendar , is itself an instance of class
Class . Thus, class
Calendar is an instance of a metaclass! It may help to drink some beer before trying to understand this.
In code, a likely implementation is:
public class Foo
{
public void doX()
{
// static method call on class Calendar
Locale[] locales = Calendar.getAvailableLocales();
// …
}
// …
}
Polymorphism is fundamental to OO design. How to show it in a sequence diagram? That's a common UML question. One approach is to use multiple sequence diagramsone that shows the polymorphic message to the abstract superclass or interface object, and then separate sequence diagrams detailing each polymorphic case, each starting with a
found polymorphic message. Figure 15.21 illustrates.
An
asynchronous message call does not wait for a response; it doesn't
block . They are used in multi-threaded environments such as .NET and Java so that new
threads of execution can be created and initiated. In Java, for example, you may think of the
Thread.start or
Runnable.run (called by
Thread.start ) message as the asynchronous starting point to initiate execution on a new thread.
The UML notation for asynchronous calls is a stick arrow message; regular synchronous (blocking) calls are shown with a filled arrow (see Figure 15.22).
Guideline This arrow difference is subtle. And when wall sketching UML, it is common to use a stick arrow to mean a synchronous call because it's easier to draw. Therefore, when reading a UML interaction diagram don't assume the shape of the arrow is correct! |
An object such as the
Clock in active objecteach instance runs on and controls its own thread of execution. In the UML, it may be shown with double vertical lines on the left and right sides of the lifeline box. The same notation is used for an
active class whose instances are active objects.active class p. 269
In Java, a likely implementation for Figure 15.22 follows. Notice that the
Thread object in the code is excluded from the UML diagram, because it is simply a consistent "overhead" mechanism to realize an asynchronous call in Java.
public class ClockStarter
{
public void startClock()
{
Thread t = new Thread( new Clock() );
t.start(); // asynchronous call to the 'run' method on the Clock
System.runFinalization(); // example follow-on message
}
// …
}
// objects should implement the Runnable interface
// in Java to be used on new threads
public class Clock implements Runnable
{
public void run()
{
while ( true ) // loop forever on own thread
{
// …
}
}
// …
}