The value of Object-Oriented Design is in allowing major structural decisions to be made before being committed to code. This allows the relationships and responsibilities of classes to be worked out efficiently and with little distraction.
The process of object-oriented design begins with an initial estimate of the classes that will be needed. The usual way to refine this estimate into a detailed object model is to work through the object interactions that are needed to support individual features or use cases.
As you discover each interaction, you add it to an interaction diagram. The most common type of interaction diagram used for this purpose is a sequence diagram. If the interaction involves a method or relationship that does not yet exist in the object mode, you either add it to the model or modify something already in the object model to accommodate the interaction.
What Is a Sequence Diagram?
UML sequence diagrams show a sequence of interactions among objects. Figure 1 shows an example of a sequence diagram.
Figure 1: Simple Sequence Diagram
This diagram shows some of the interactions among the objects involved in running a toll gate in a toll plaza. A TollManager, who is some kind of external actor, causes a TollBooth object’s start operation to be called. The start operation runs asynchronously of what the TollManager is doing. You know that it runs asynchronously of what the TollManager is doing because of the open arrowhead (). This means that after initiating the start operation, the TollManager does not wait for the operation to finish; it just continues to go about its business at the same time.
The start operation repeatedly calls the TollBooth object’s collectNextToll operation. You know that the calls to the collectNextToll operation are repeated indefinitely because of the asterisk ( *) that precedes the name of the operation.
The start operation’s calls to the collectNextToll operation are synchronous. This means that the start operation must wait for the collectNextToll operation to finish before continuing. You know that the calls are synchronous because of the solid closed arrowhead ().
The collectNextToll operation makes a synchronous call to two other operations. It calls the TollBasket object’s collectToll operation. Next, it calls the TollGate object’s raiseTollGate operation.
Sequence Diagram Elements
Before moving on to the next topic, look at UML terminology for some of the elements of a sequence diagram. Figure 2 is the sequence diagram you saw previously, but with some annotations added.
Figure 2: Annotated Sequence Diagram
Stick figures represent an external actor. Boxes at the top represent an object. You know that they are objects rather than classes because the names in the boxes are underlined. Because the names in Figure 2 are preceded by a colon (:), you know that the names are the names of the class that each object is an instance of.
Below each actor and object is a dashed vertical line called a life line. Each object’s and actor’s life line is used to organize things that happen related to the object or actor with the earliest at the top and the latest at the bottom.
Vertical rectangles placed along a life line that are called activations. Each activation represents the running of an operation associated with the life line’s actor or object.
Guarded Repetition in a Sequence Diagram
You have seen how a sequence diagram represents calls to operations and indefinite repetitions of calls that are like infinite loops. Conditional repetitions can also be represented in a sequence diagram.
If an operation is to be conditionally called multiple times, similar to a call in a while loop, this can be captured by putting the condition in square brackets like this:
The preceding indicates that while listIsOpen is true, calls will continue to be made to the collectNextToll operation.
The UML terminology for one of these conditions in square brackets is called a guard. The guard in this example is very simple in that it consists of just a single condition. Guards can contain whatever comparisons and logical connectors are needed to express more complicated conditions.
It is also possible to indicate that an operation is to be called some particular number of times, which is similar to a for loop. The way this is done is to indicate in the guard that a variable is to be assigned to a range of values. The UML specification does not say how this must be done. Figure 3 shows a common way to write this.
Figure 3: Operation Repeated a Fixed Number of Times
Notice that the syntax used in Figure 3 specifies a variable in the guard to contain the values. The same variable is also used as a parameter to the logItem operation. This ability to associate variables with values allows a sequence diagram to represent enough data flow to make the structure of loops clear. Variables also can be used to make it clear how each operation gets visibility to objects.
Before moving on to the next topic, there are a couple of things to notice about the sequence diagram in Figure 3. The first thing is that it looks different than the diagram in Figure 1. This is because they were drawn with different tools.
The UML standard allows for some flexibility in the way that the elements of a sequence diagram are drawn. Different tools draw some elements differently and some even have tool-specific extensions.
The other thing to notice about the sequence diagram in Figure 3 is the punctuation in the names in the objects. The object on the right has two names separated by a colon (:). The name to the right of the colon, Logger, is the name of the class that the object is an instance of. The name to the left of the colon, SafetyLog, is a name that identifies the specific object within the sequence diagram. This name can be used in such places as guard expressions and parameters to operations.
In a sequence diagram, you can associate the result returned by an operation with a variable. This is often used with conditional operations, as shown in the example in Figure 4.
Figure 4: Set and Test the Value of a Variable
Figure 4 shows a number of new things you have not seen in previous sequence diagrams. The first thing that you look at in Figure 4 is a call to an operation whose result becomes associated with a variable.
This says the an operation named isCurrent is called, that the isCurrent operation returns a boolean result, and that the variable currentFlag gets the result value returned by the isCurrent operation.
The next interaction you look at is similar to an if statement. It consists of a call to an operation with a guard.
The call to grantPermission happens if, and only if, currentFlag is true.
Another important feature of the sequence diagram in Figure 4 is that it includes the creation and destruction of an object. Notice that the first interaction is shown as a dashed line from the PermissionRule object to the License object. The line goes to an object rather than to the object’s life line because the interaction creates the object. The License object is not at the top of the diagram because the License object does not exist until this interaction creates the License object.
Something else to notice about the License object in Figure 4 is that its life line does not go all the way down to the bottom of the sequence diagram. Instead, it ends with a . This at the bottom of a life line indicates the destruction of the object.
Other Sequence Diagram Features
There are a few other features of the sequence diagram in Figure 4 to notice.
The at the upper left corner of the diagram is the diagram’s title. The sd at the beginning of the title indicates that the diagram is a sequence diagram.
Every interaction in Figure 4 is preceded by a sequence number. There are a variety of numbering schemes that can be used in a sequence diagram. However, the numbering used in a sequence diagram should indicate the order in which the interactions happen.
The last thing to notice about Figure 4 is the activation shown for interaction 1.3. This is a call to an operation associated with the PermissionRule object while there is already on operation in progress associated with the same object. Because the operations associated with the same object are nested in time, the activations are shown as nested.
This article has shown you how to use UML to model interactions and other dynamic relationships between objects. During the object-oriented design process, discovering and modeling the interactions and relationships is a way to refine your object model. The sequence diagram features you have learned about are sufficient for modeling most programs.
The UML specification specifies other features to express additional subtleties and to make sequence diagrams more compact. Some modeling tools extend sequence diagrams to capture lower-level details.
About the Author
|Mark Grand is a consultant and book author with over 30 years of experience who specializes in Distributed Systems, Object-Oriented Design, and Java. He was the architect of the first commercial business-to-business e-commerce product for the Internet.
Mark Grand is most widely known for his best selling design pattern books. Mark has taught for U.C. Berkeley, Sun, and other organizations.
Mark is based in the Atlanta area. He has been involved with object-oriented programming and design since 1982.