Applying UML and Patterns: An Introduction to ObjectOriented Analysis and Design and Iterative Development, Third Edition [Electronic resources]

Craig Larman

نسخه متنی -صفحه : 472/ 199
نمايش فراداده

15.4. Basic Sequence Diagram Notation

Lifeline Boxes and Lifelines

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.

lifeline boxes p. 226

Messages

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.

Figure 15.7. Messages and focus of control with execution specification bar.

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.

Focus of Control and Execution Specification Bars

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.

Illustrating Reply or Returns

There are two ways to show the return result from a message:

  1. Using the message syntax

    returnVar = message(parameter) .

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

Figure 15.8. Two ways to show a return result from a message.

Messages to "self" or "this"

You can show a message being sent from an object to itself by using a nested activation bar (see Figure 15.9).

Figure 15.9. Messages to "this."

Creation of Instances

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.

Figure 15.10. Instance creation and object lifelines.

[View full size image]

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

Object Lifelines and Object Destruction

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

Figure 15.11. Object destruction.

Diagram Frames in UML Sequence Diagrams

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.

Figure 15.12. Example UML frame.

[View full size image]

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.

Looping

The LOOP frame notation to show looping is shown in Figure 15.12.

Conditional Messages

An OPT frame is placed around one or more messages. Notice that the guard is placed

over the related lifeline. See Figure 15.13.

Figure 15.13. A conditional message.

Conditional Messages in UML 1.x StyleStill Useful?

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.

Figure 15.14. A conditional message in UML 1.x notationa simple style.

Guideline : Use UML 1 style only for simple single messages when sketching.

Mutually Exclusive Conditional Messages

An ALT frame is placed around the mutually exclusive alternatives. See Figure 15.15.

Figure 15.15. Mutually exclusive conditional messages.

Iteration Over a Collection

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.

Figure 15.16. Iteration over a collection using relatively explicit notation.

[View full size image]

Figure 15.17. Iteration over a collection leaving things more implicit.

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.

Nesting of Frames

Frames can be nested. See Figure 15.18.

Figure 15.18. Nesting of frames.

How to Relate Interaction Diagrams?

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.

Figure 15.19. Example interaction occurrence,

sd and

ref frames.

[View full size image]

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

    AuthenticateUser

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

Messages to Classes to Invoke Static (or Class) Methods

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

Figure 15.20. Invoking class or static methods; showing a class object as an instance of a metaclass.

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();

// …

}

// …

}

Polymorphic Messages and Cases

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.

Figure 15.21. An approach to modeling polymorphic cases in sequence diagrams.

[View full size image]

Asynchronous and Synchronous Calls

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

Figure 15.22. Asynchronous calls and active objects.

[View full size image]

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

{

// …

}

}

// …

}