本章深入探討 UML 類別圖(Class Diagrams)的各種細節與修飾符號。作者的核心觀點是:類別圖有大量的細節可以添加,但大多數時候不需要。本章呈現的是作者實際使用的子集。

基礎語法#

類別(Classes)#

Figure 19.1: Class icon

類別圖中的矩形通常分為三個區間:

  • 類別名稱
  • 屬性(Attributes):成員變數,前綴 - 表示 private、# 表示 protected、+ 表示 public
  • 方法(Methods):成員函式,可見性標記規則相同

關聯(Association)#

關聯代表一個類別持有另一個類別的實例參考。在圖上以連線表示,箭頭指向被參考的類別。關聯線旁可以標記:

  • 關聯名稱
  • 方向箭頭:表示哪一方持有參考
  • 多重性(Multiplicity):表示持有的數量

繼承(Inheritance)#

Figure 19.5: Inheritance

繼承以空心三角箭頭表示,箭頭指向父類別(基底類別)。

介面實作(Realizes)#

Figure 19.6: Realizes relationship

介面實作以虛線 + 空心三角箭頭表示。另外也可以使用棒棒糖符號(Lollipop Notation)——在類別旁畫一個小圓圈並標記介面名稱。

範例:ATM 類別圖#

作者以 ATM 系統為例,展示如何組織一張較大的類別圖。良好的類別圖應該具備:

  • 分區(Zoning):相關的類別群組放在一起
  • 一致的慣例:例如繼承箭頭統一朝上、關聯統一朝右
  • 清楚的層次結構

細節(The Details)#

補充: 以下細節大多數時候不需要用到。只有在特定場景下需要精確表達某種關係時,才考慮使用這些修飾符號。

類別刻板印象(Class Stereotypes)#

Figure 19.9: interface class stereotype

Class stereotypes 使用法式引號(guillemet << >>)標記在類別名稱上方:

  • <<interface>>:所有方法皆為抽象、不可有實例變數——完全對應 C# 的 interface
    • 簡寫方式:用 <<I>> 取代完整的 <<interface>>(非標準 UML,但白板上更方便)
  • <<utility>>:所有成員皆為 static——對應 C# 的靜態工具類別

Figure 19.10: utility class stereotype

也可以自訂 stereotypes,例如 <<persistent>><<struct>><<C-API>> 等。

抽象類別(Abstract Classes)#

在 UML 中有兩種表示抽象類別的方式:

  • 斜體字:將類別名稱或方法名稱以斜體呈現
  • {abstract} 屬性:標記在類別名稱下方

Figure 19.12: Unofficial denotation of abstract classes

技巧: 白板上很難寫斜體字,{abstract} 又太冗長。作者使用非標準的 {A} 標記作為簡寫,更適合即時溝通。

屬性(Properties)#

Figure 19.13: Properties

Properties 是附加在類別上的元資料,以 {name=value} 格式寫在類別名稱下方。例如 {author=Martin, date=20020429}

實務上除了 {abstract} 之外,其他 property 幾乎不會用到。

聚合(Aggregation)#

Figure 19.15: Illegal cycles of aggregation between instances

聚合是關聯的一種特殊形式,暗示整體/部分(Whole/Part)的關係,以空心菱形表示。

  • 實作上與普通關聯完全相同——在 C# 程式碼中看不出差異
  • UML 規範對聚合的定義非常模糊,導致不同人有不同解讀
  • 唯一的硬性規則是:聚合的實例不能形成(Cycle)

注意: 作者建議完全不要使用聚合關係。UML 2.0 甚至差點將它移除。它帶來的混亂遠大於價值。

組合(Composition)#

組合是聚合的更強形式,以實心菱形表示。

Figure 19.17: Illegal composition

組合的規則比聚合更嚴格:

  • 一個 ward(被擁有者)在同一時間只能被一個 owner 擁有
  • owner 負責 ward 的生命週期:owner 銷毀時 ward 必須一起銷毀,owner 複製時 ward 必須一起複製

Figure 19.18: Deep copy implied by composition

在 C# 中,由於 Garbage Collector 管理物件生命週期,組合關係的主要用途是表示深拷貝(Deep Copy)語意。但在實務中使用頻率不高。

多重性(Multiplicity)#

Figure 19.19: Simple multiplicity

多重性標記在關聯線的遠端,表示持有的物件數量:

  • 1 — 恰好一個
  • *0..* — 零到多個
  • 0..1 — 零或一個
  • 1..* — 一到多個
  • 3..5 — 三到五個

關聯刻板印象(Association Stereotypes)#

關聯也可以加上 stereotypes 來表達更精確的語意:

  • <<create>>:來源類別建立目標類別的實例(典型的 Factory)
  • <<local>>:來源類別在方法中建立目標的區域變數
  • <<parameter>>:來源類別透過方法參數取得目標的參考
  • <<delegate>>:來源類別將方法呼叫轉發給目標(常見於 Proxy、Decorator、Composite 模式)

虛線箭頭搭配 <<parameter>> 是常見的慣用法,用來表示方法參數的依賴關係。

巢狀類別(Nested Classes)#

Figure 19.21: Nested class

巢狀類別以關聯線加上交叉圓圈來表示。

關聯類別(Association Classes)#

Figure 19.22: Association class

當多重關聯需要說明容器類別的具體型別時,可以使用關聯類別——以虛線連接到關聯線上的一個類別。

關聯限定詞(Association Qualifiers)#

Figure 19.24: Association qualifier

當關聯是透過某種 key 或 token(而非直接的物件參考)實現時,可以使用關聯限定詞。例如透過資料庫 key 查找關聯的物件。

本章小結#

UML 類別圖有大量的修飾符號與細節,但作者的建議是極簡主義

  • 學會基礎語法(類別、關聯、繼承、介面)就足以應付日常需求
  • 細節符號(聚合、組合、多重性等)只在確實需要時才使用
  • 用太少的 UML 永遠比用太多好

重點: 花大量時間去精通 UML 的每一個符號,最終只會讓你成為「UML 律師」——能寫出沒有人看得懂的精美文件。這不是 UML 的初衷。