Skip to content
Ahmet Çelik

Chapter 7: Object Design and Interaction Diagrams

COMP302 22 minute read

Source files used: Lecture 7 - Object Design Interaction Diagrams.

A focused guide to object design and UML interaction diagrams for the COMP302 Midterm 1. It covers static vs dynamic modeling, CRC cards, and the notation of sequence and communication diagrams, including how to draw a diagram from Java code. Guide 6 set the layers; this guide designs how the objects inside them collaborate, starting from the system operations of Guide 5.

Roadmap: 1 OOA/D and UP → 2 Inception and Requirements → 3 Use Cases → 4 Domain Models → 5 SSDs and Contracts → 6 Logical Architecture → 7 Interaction Diagrams

On to Object Design

How Do Developers Design Objects?

  1. Code: design while coding, from a mental model straight to code.
  2. Draw, then code: sketch some UML on a whiteboard or in a UML CASE tool, then switch to coding in an IDE.
  3. Only draw: a tool generates everything from the diagrams (still with text code attached to the UML elements).

The drawing overhead should be worth the effort, so the lecture promotes lightweight drawing before coding.

Agile Modeling and UML CASE Tools

Agile modeling aims to reduce drawing overhead:

  • model to understand and communicate, not to document,
  • use whiteboards (10 in a room, not 2), markers, digital cameras, and printers to capture “UML as sketch”,
  • model with others,
  • create several models in parallel: five minutes on a wall of interaction diagrams, then five minutes on a wall of related class diagrams.

UML CASE tools are still useful: choose one that integrates with the IDE, code, then reverse engineer the code to see a UML big picture. Wall sketching and a CASE tool are complementary. For a 3-week iteration, spend a few hours or at most one day near the start drawing UML for the hard, creative parts of the design, then switch to coding.

Static vs Dynamic Modeling

Dynamic modelsStatic models
UML diagramsinteraction diagrams (sequence, communication), state machine diagrams, activity diagramsclass diagrams, package diagrams, deployment diagrams
What they designthe logic and behavior of the code: the method bodiespackages, class names, attributes, method signatures (not method bodies)

The lecture calls the dynamic models the more interesting, difficult, and important diagrams to create.

Key Insight: The dice game from Guide 1 shows both: a class diagram (DiceGame with play(), Die with faceValue and roll()) is static; the sequence diagram of play() calling roll() is dynamic.

Object Design Skill Over UML Notation Skill

Knowing how to think and design in objects is more valuable than knowing UML notation. While drawing, the real questions are:

  • What are the responsibilities of the object?
  • Who does it collaborate with?
  • What design patterns should be applied?

Drawing UML is a reflection of design decisions. Fundamental object design needs principles of responsibility assignment and design patterns (the course’s later topics).

CRC Cards

Class Responsibility Collaboration (CRC) cards are a popular text-oriented modeling technique: paper index cards, one card per class, listing the class’s responsibilities on the left and its collaborators on the right.

+---------------------------------+---------------------+
| Drawing                         | (collaborators)     |
|---------------------------------|                     |
| Holds Figures.                  | Figure              |
| Accumulates updates, refreshes  | DrawingView         |
| on demand.                      | DrawingController   |
+---------------------------------+---------------------+

Interaction Diagrams

Two Kinds

UML interaction diagrams illustrate how objects interact via messages; they are used for dynamic object modeling.

  • Sequence diagrams use a fence format: each new object is added to the right.
  • Communication diagrams use a graph or network format: objects can be placed anywhere.
TypeStrengthsWeaknesses
sequenceclearly shows the sequence or time ordering of messages; large set of detailed notation optionsforced to extend to the right when adding new objects; consumes horizontal space
communicationspace economical; flexibility to add new objects in two dimensionsmore difficult to see the sequence of messages; fewer notation options

From Code to Diagram

The lecture’s first example. Legend for every diagram in this guide: : is a lifeline (dashed in UML), [ ] is an execution specification (activation) bar, o-- is a found message, ---> is a synchronous message, <- - - is a reply, and - - -> is a creation message.

public class A {
    private B myB = new B();   // myB exists before doOne() is ever called

    public void doOne() {
        myB.doTwo();           // first message
        myB.doThree();         // second message
    }
}
                 :A                myB : B
                  :                   :
  o--doOne()---->[ ]                  :
                 [ ] doTwo()          :
                 [ ]---------------->[ ]
                 [ ] doThree()        :
                 [ ]---------------->[ ]
                  :                   :

The same interaction as a communication diagram:

  doOne()
 -------->+-----+
          | :A  |
          +-----+
             |     1: doTwo()    |
             |     2: doThree()  v
        +---------+
        | myB : B |
        +---------+

Sequence Diagram Notation

Lifeline Boxes

Lifeline labelMeaning
:Salean unnamed instance of class Sale
s1 : Salea named instance
«metaclass» Fontthe class Font itself (an instance of a metaclass), for static calls
sales: ArrayList<Sale>an instance of ArrayList parameterized to hold Sale objects
sales[ i ] : Saleone Sale selected from the sales collection
x : Listan object typed by an interface (legal in UML 2, not in UML 1.x)

A singleton object (only one instance can exist, accessed through the Singleton pattern) is marked with a 1 in the upper right corner of its lifeline box.

Messages, Found Messages, and Activation Bars

  • The starting message is a found message, drawn with an opening solid ball: the sender is not specified, not known, or the message comes from a random source.
  • A typical synchronous message is a solid line with a filled arrowhead.
  • The execution specification bar (activation bar) shows the focus of control: the operation is on the call stack.

Replies and Returns

There are two ways to show a return result:

  1. the message syntax returnVar = message(parameter), or
  2. a reply (return) message: a dashed line at the end of the activation bar.
            :Register                   :Sale
                :                         :
  o--doX()---->[ ]                        :
               [ ] d1 = getDate()         :
               [ ]---------------------->[ ]
               [ ] getDate()              :
               [ ]---------------------->[ ]
               [ ] aDate                 [ ]
               [ ]< - - - - - - - - - - -[ ]
                :                         :

Messages to Self

A message from an object to itself (to this) is drawn with a nested activation bar:

          :Register
              :
  o--doX()-->[ ]
             [ ]---+  clear()
             [ ]<--+      (nested bar on :Register)
              :

Creating and Destroying Instances

Creation uses a dashed line (UML-mandated) with a create(...) message, and the new object’s box is placed at its creation “height”:

          :Register                       :Sale
              :                             :
   makePayment(cashTendered)                :
  o--------->[ ]                            :
             [ ] makePayment(cashTendered)  :
             [ ]-------------------------->[ ]
             [ ]                           [ ] create(cashTendered)
             [ ]                           [ ]- - - - - - - - - - - ->:Payment
             [ ]                           [ ] authorize()                :
             [ ]                           [ ]-------------------------->[ ]
              :                             :                             :
public class Sale {
    private Payment payment;

    public void makePayment(Money cashTendered) {
        payment = new Payment(cashTendered);   // the create message
        // ...
    }
}

Explicit destruction is shown with a «destroy» stereotyped message and a large X ending the lifeline. Use it in languages without garbage collection, or to stress that an object is no longer usable (such as a closed database connection).

Exam Trap #1: Drawing creation as a normal solid message to a box at the top of the diagram. A created object’s box starts at the creation height, and the create arrow is dashed.

Frames: loop, opt, alt

UML uses frames (regions or fragments of the diagram) for conditional and looping constructs. A frame has an operator (label) and a guard (conditional clause).

FrameMeaningLecture example
loop [guard]repeat the fragment while the guard is trueloop [more items] around enterItem
loop(n)repeat n timesnested inside an opt frame
opt [guard]conditional message: execute only if the guard is trueopt [color = red] around calculate
alt [guard] / [else]mutually exclusive alternatives (if/else), separated by a dashed line[x < 10] calculate on :B, [else] calculate on :C
sd Name / ref Namea named diagram, and a reference to itAuthenticateUser
         :Foo                       :Bar
          :         xx()             :
          :------------------------->:
   +------:--------------------------:---+
   | opt [color = red]               :   |
   |      :         calculate()      :   |
   |      :------------------------->:   |
   +------:--------------------------:---+
          :         yy()             :
          :------------------------->:

Frames can be nested (an opt frame containing a loop(n) frame). The older UML 1 notation for a conditional message puts the guard on the message itself: [ color = red ] calculate.

Iteration Over a Collection

UML has no official idiom for sending the same message to every member of a collection; the lecture shows two alternatives.

  • Explicit: a loop [i < lineItems.size] frame, a lifeline lineItems[i] : SalesLineItem (the [i] is a selector expression), and an action box i++ on the Sale lifeline.
  • Implicit: a plain loop frame around st = getSubtotal() to lineItems[i] : SalesLineItem.

Both describe this code:

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();   // one getSubtotal message per item
            total.add(subtotal);
        }
        return total;
    }
}

Relating Diagrams: sd and ref

An interaction occurrence is a reference to an interaction within another interaction. It simplifies a diagram by factoring out a portion. Two related frames create it:

  • a frame around an entire sequence diagram, tagged sd and a name, such as sd AuthenticateUser,
  • a frame tagged ref in another diagram, which refers to that named diagram; this is the actual interaction occurrence. It covers the same lifelines as the sd diagram (for example, :B and :C).

Messages to Classes (Static Methods)

A static method call is a message to a lifeline labeled as a class, more precisely an instance of a metaclass. In Java, all classes are instances of class Class; in .NET, of class Type.

            :Foo                          «metaclass» Calendar
              :                                     :
  o--doX()-->[ ]                                    :
             [ ] locales = getAvailableLocales()    :
             [ ]---------------------------------->[ ]
              :                                     :
public void doX() {
    Locale[] locales = Calendar.getAvailableLocales();   // static call on Calendar
}

Polymorphic Messages and Cases

Polymorphism is fundamental to OO design. One approach: draw the polymorphic message to the abstract superclass or interface object and stop there; then draw a separate diagram for each concrete case, each starting with a found polymorphic message.

            :Register            :Payment {abstract}
                :                         :
  o--doX()---->[ ]                        :
               [ ] authorize()            :
               [ ]---------------------->[ ]   stop here: no further detail
                :                         :

              :DebitPayment           :Foo
                    :                   :
  o--authorize()-->[ ]                  :
                   [ ] doA()            :
                   [ ]---------------->[ ]
                   [ ] doB()            :
                   [ ]---------------->[ ]
                    :                   :

             :CreditPayment           :Bar
                    :                   :
  o--authorize()-->[ ]                  :
                   [ ] doX()            :
                   [ ]---------------->[ ]
                    :                   :

Here Payment is an abstract superclass with an abstract authorize(); CreditPayment and DebitPayment implement it.

Asynchronous vs Synchronous Calls

  • A synchronous (blocking) call is a filled arrowhead; the caller waits.
  • An asynchronous call does not wait for a response and does not block. It is drawn with a stick (open) arrowhead. Asynchronous calls start new threads in Java and .NET: think of Thread.start (which calls Runnable.run) as the asynchronous starting point.
  • An active object runs on and controls its own thread, such as a Clock that implements Runnable. It is drawn with double vertical lines on the left and right of its box; the same notation marks an active class.
public class ClockStarter {
    public void startClock() {
        Thread t = new Thread(new Clock());
        t.start();                    // asynchronous: ends up calling Clock.run()
        System.runFinalization();     // example follow-on message
    }
}

Exam Trap #2: Using the same arrowhead for every message. Filled arrowhead: synchronous. Stick arrowhead: asynchronous. Dashed line: reply or creation.

Communication Diagram Notation

  • A link is a connection path between two objects: a form of navigation or visibility between them. Formally, it is an instance of an association.
  • There can be only one link between two objects. All messages, in both directions, flow along that same link.
  • Each message has a message expression and a small arrow showing its direction.
  • A sequence number shows the order of messages in the current thread of control.
  • A message to self is drawn as a link from the object back to itself.
                 1: makePayment(cashTendered) -->
                 2: foo() -->
 +------------+                                      +-------+
 | : Register |--------------------------------------| :Sale |
 +------------+                                      +-------+
                 <-- 2.1: bar()

Message Numbering

  1. The first message is not numbered (msg1 is unnumbered).
  2. Messages sent while handling an incoming message are nested: prepend the incoming message’s number. Inside message 1, the messages are 1.1, 1.2, …; inside message 2, they are 2.1, 2.2, …

The lecture’s example, in order: msg1 (to :A), 1: msg2 (A to B), 1.1: msg3 (B to C), 2: msg4 (A to C), 2.1: msg5 (C to B), 2.2: msg6 (C to D).

Creation, Conditions, and Iteration

SituationCommunication diagram syntax
creation1: create(cashier) to :Sale (read as a constructor call); or mark the new object :Sale {new}; or use «create» 1: make(cashier) for a less obvious name
conditional message1 [color = red] : calculate (sent only if the clause is true)
mutually exclusive paths1a [test1] : msg2 and 1b [not test1] : msg4; their nested messages are 1a.1 and 1b.1; a later 2: msg6 runs after either path
iteration1 * [i = 1..n] : num = nextInt (a * plus an optional iteration clause)
iteration over a collection1 * [i = 1..n] : st = getSubtotal to lineItems[i] : SalesLineItem; or the less precise 1 * : st = getSubtotal
static method1: locs = getAvailableLocales to «metaclass» Calendar
polymorphismseparate diagrams for each concrete case, as in sequence diagrams
asynchronous callstick arrow, as in sequence diagrams (2: run to an active :Clock)

Exam Trap #3: Numbering the first message 1:, or numbering nested messages flat. The incoming message is unnumbered, and nested calls inherit their parent’s number.

WRONG:   1: fnA, 2: fnB, 3: fnX, 4: fnY, 5: fnC, 6: fnZ
CORRECT: fnA, 1: fnB, 1.1: fnX, 1.2: fnY, 2: fnC, 2.1: fnZ

Exam-Style Practice Problems

Problem 1: Sequence Diagram From Code

Question: The Fall 2024 Midterm 1 study sheet: draw the sequence diagram for this code, starting from a call to fnA on an object of class A (include all participating objects).

public class A {
    private B myB = new B();

    public void fnA() {
        int p;
        p = myB.fnB();
        myB.fnC();
    }
}

public class B {
    private C myC = new C();

    public int fnB() {
        myC.fnX();
        return myC.fnY();
    }

    public void fnC() {
        myC.fnZ();
    }
}

Answer:

                 :A                myB : B             myC : C
                  :                   :                   :
  o--fnA()------>[ ]                  :                   :
                 [ ] p = fnB()        :                   :
                 [ ]---------------->[ ]                  :
                 [ ]                 [ ] fnX()            :
                 [ ]                 [ ]---------------->[ ]
                 [ ]                 [ ] fnY()            :
                 [ ]                 [ ]---------------->[ ]
                 [ ] fnC()            :                   :
                 [ ]---------------->[ ]                  :
                 [ ]                 [ ] fnZ()            :
                 [ ]                 [ ]---------------->[ ]
                  :                   :                   :
  • myB and myC are created when A and B are constructed, before fnA runs, so no create messages appear.
  • p = fnB() shows the return value; a dashed reply line from myB is an equivalent option.
  • fnX and fnY are nested inside fnB’s activation; fnZ is nested inside fnC’s.

Problem 2: Sequence Diagram With Creation

Question: (Study sheet) Draw the sequence diagram for a call to the startGame method of a computer game object, which creates a new game session object and calls startGameSession on it; that in turn creates a new Level object and calls initializeLevel on it.

Answer:

              :ComputerGame
                    :
  o--startGame()-->[ ]
                   [ ] create()
                   [ ]- - - - - - - ->:GameSession
                   [ ] startGameSession()   :
                   [ ]-------------------->[ ]
                   [ ]                     [ ] create()
                   [ ]                     [ ]- - - - - - - - - >:Level
                   [ ]                     [ ] initializeLevel()    :
                   [ ]                     [ ]-------------------->[ ]
                    :                       :                       :

Each new object’s box sits at the height of its dashed create message, and :Level is created by :GameSession, not by :ComputerGame.

Problem 3: Convert to a Communication Diagram

Question: Redraw Problem 1 as a communication diagram.

Answer:

  fnA()
 ------>+-----+
        | :A  |
        +-----+
           |     1: p = fnB()   |
           |     2: fnC()       v
      +---------+
      | myB : B |
      +---------+
           |     1.1: fnX()     |
           |     1.2: fnY()     |
           |     2.1: fnZ()     v
      +---------+
      | myC : C |
      +---------+

One link per pair of objects; all messages between them ride on that link.

Problem 4: Static vs Dynamic

Question: (Study sheet) What is the difference between static and dynamic modeling?

Answer: Dynamic models (sequence, communication, state machine, activity diagrams) design behavior: the logic of method bodies. Static models (class, package, deployment diagrams) design definitions: packages, class names, attributes, and method signatures, but not method bodies.

Common Exam Traps

1. Creation Drawn as a Normal Message

WRONG:   :Payment box at the top, solid arrow "new Payment()"
CORRECT: dashed create(...) arrow ending at the :Payment box,
         drawn at its creation height

Why: The dashed line for creation is UML-mandated.

2. Creating Objects That Already Exist

WRONG:   fnA diagram starts with create(myB) and create(myC)
CORRECT: myB and myC already exist (field initializers), so fnA starts the messages

Why: The diagram starts at the found message; earlier construction is not part of it.

3. Missing Nesting of Activation Bars

WRONG:   fnX drawn from :A to myC after fnB
CORRECT: fnX drawn from myB to myC, inside myB's fnB activation

Why: The sender of a message is the object whose method makes the call.

4. Forgetting the Found Message

WRONG:   the diagram begins with :A sending fnB()
CORRECT: o--fnA()--> :A, then :A sends fnB()

Why: The starting message (found message, solid ball) is where the interaction begins.

5. Communication Numbering

WRONG:   1: fnA, 2: fnB, 3: fnX
CORRECT: fnA (unnumbered), 1: fnB, 1.1: fnX

Why: The first message is unnumbered, and nesting is shown by prepending the parent number.

WRONG:   one link line per message between :Register and :Sale
CORRECT: a single link; all messages flow along it

Why: There can be only one link between two objects.

7. Polymorphism in One Giant Diagram

WRONG:   authorize() to :Payment, then both doA/doB and doX on one diagram
CORRECT: stop at :Payment {abstract}; one more diagram per concrete subclass

Why: Each concrete case starts with its own found polymorphic message.

8. Static Calls to an Instance

WRONG:   :Calendar receives getAvailableLocales()
CORRECT: «metaclass» Calendar receives getAvailableLocales()

Why: A static method belongs to the class, an instance of a metaclass.

9. Synchronous vs Asynchronous Arrowheads

WRONG:   run() to the active :Clock drawn with a filled arrowhead (caller waits)
CORRECT: run() drawn with a stick arrowhead (asynchronous: the caller goes on)

Why: An asynchronous call does not block the caller.

10. UML Notation Over Design

WRONG:   "Good object design = perfect UML notation."
CORRECT: "Good object design = good responsibilities, collaborations, and patterns."

Why: The lecture says object design skill matters more than UML notation skill.

Final Tips for the Midterm

  • Trace the code before drawing: list the calls in order (here fnA, fnB, fnX, fnY, fnC, fnZ) and note who sends each one.
  • Draw the four basics every time: found message, lifeline boxes with name : Class, activation bars, and dashed creates.
  • Show returns one consistent way: p = fnB() on the message, or a dashed reply line.
  • Know the frames: loop, opt, alt (with [else]), and sd/ref.
  • Number communication diagrams correctly: unnumbered first message, then 1, 1.1, 1.2, 2, 2.1.
  • Explain static vs dynamic modeling in one breath: structure and signatures vs behavior and method bodies.

Good luck on the midterm! You’ve got this.