本章深入探討序列圖(Sequence Diagrams),它是 UML 中最常使用的動態模型。序列圖非常適合用來解釋物件之間的協作方式,但不應該被濫用——過多的序列圖與沒有序列圖一樣糟糕。
重點: 不要為系統中的每一個方法都畫序列圖。只在需要解釋一組物件如何協作來完成某個行為時才使用。大多數時候,程式碼本身比序列圖更具表達力。
基本語法#

Figure 18.1: Typical sequence diagram
序列圖的基本元素:
- 生命線(Lifeline):從物件向下延伸的虛線
- 訊息(Message):水平箭頭,對應方法呼叫
- 啟動框(Activation):生命線上的窄矩形,表示方法正在執行中
- 資料標記(Data Token):在訊息旁標註的參數或回傳值
物件的建立與銷毀#

Figure 18.2: Creating an object

Figure 18.3: Releasing an object to the garbage collector
- 建立:訊息箭頭指向物件圖示本身(而非生命線)
- 銷毀:在 C# 中由 Garbage Collector 處理,以 X 符號標示在生命線底部
簡單迴圈#

Figure 18.4: A simple loop
迴圈可以用矩形框搭配 *[condition] 標記來表示。
Cases 與 Scenarios#
序列圖應該保持小而聚焦。當一個場景變得過於複雜時,應該拆分成多張圖。

Figure 18.5: An overly complex sequence diagram
注意: 上圖就是一個反面教材——試圖在一張序列圖中塞入太多資訊。這種圖比程式碼更難理解,失去了使用 UML 的意義。
正確的做法是畫出高層次的概觀,只呈現物件之間的主要互動:

Figure 18.7: A high-level view
技巧: 好的序列圖應該能在三十秒內被理解。如果你的圖需要花五分鐘才能看懂,它就太複雜了。
進階概念#
迴圈與條件#

Figure 18.8: Sequence diagram with loops and conditions
UML 2.0 引入了 loop 和 alt 框架來表示迴圈與條件判斷。然而作者建議避免在序列圖中使用過多的流程控制——這些邏輯用程式碼表達更加清楚。
需要時間的訊息#
當訊息的傳遞需要顯著的時間(例如網路通訊),可以用傾斜的箭頭來表示:

Figure 18.10: Failed phone call
傾斜箭頭的好處是能直觀地呈現競態條件(Race Condition)——當兩個訊息在傳輸途中交錯時,可能產生意想不到的行為。
非同步訊息(Asynchronous Messages)#

Figure 18.11: Asynchronous message

Figure 18.12: Older, better way to depict asynchronous messages
非同步訊息的表示方式:
- UML 2.0:使用空心箭頭
- 舊版 UML:使用半箭頭(作者認為這個符號更直覺)
非同步訊息代表送出者不等待回應就繼續執行,適合用在事件驅動或訊息佇列的場景。
多執行緒(Multiple Threads)#

Figure 18.13: Multiple threads of control
多執行緒可以透過在訊息標號前加上執行緒識別碼來表示,例如 T1:message。
活躍物件(Active Objects)#

Figure 18.14: Active object
活躍物件以粗邊框表示,代表該物件持有自己的執行緒。
傳送訊息給介面#

Figure 18.15: Simple logger design

Figure 18.16: Sending to an interface

Figure 18.17: Sending to a derived type through an interface
當訊息的接收者是一個介面(Interface)而非具體類別時,可以用介面型別來命名物件。這在描述多型(Polymorphism)行為時非常有用。
本章小結#
序列圖是 UML 中最實用的動態模型,但必須遵循少即是多的原則:
- 只在需要解釋物件協作時使用
- 保持圖面簡潔,避免塞入過多流程控制邏輯
- 程式碼能清楚表達的邏輯,不需要用序列圖重複表達
補充: 作者的經驗法則:寧可畫太少,也不要畫太多。一張精心選擇的序列圖勝過十張機械性產出的圖。