Read this post in: de_DEen_USes_ESfr_FRhi_INid_IDjapl_PLpt_PTru_RUvizh_CN

UML類圖的全面指南(程式碼即圖示)

💡 注意:所有圖示均以PlantUML格式提供。您可使用Visual Paradigm 圖示即程式碼.


🔹 UML 簡介

什麼是 UML?

「統一模型語言(UML)是一種通用的視覺化建模語言,用於指定、視覺化、建構和文件化軟體系統的各項產物。」 — Rumbaugh 等人,1999

主要特徵:

  • 🎨 視覺符號:用於建模系統的圖形語法

  • 📐 標準化:自1997年起由對象管理組織(OMG)採用的標準

  • 🔧 語言,而非方法:定義符號,而非流程

  • 🌐 範圍廣泛:可建模業務流程、系統功能、程式碼結構與資料庫結構

UML 不是什麼

誤解 事實
一種開發方法論 僅是一種建模符號
一種程式語言 抽象規格語言
僅適用於物件導向程式設計 適用於資料庫、商業模型等
在所有方面都精確定義 早期版本中仍存在一些語義上的模糊性

🔹 歷史與標準化

演進時間軸

The Evolution of Unified Modeling Language (UML)

1965-1970:Simula-67(第一種物件導向語言)
     ↓
1970年代-1980年代:Xerox PARC 的 Smalltalk
     ↓
1984:Bjarne Stroustrup 發表 C++
     ↓
1988-1992:物件導向方法的蓬勃發展(Booch、OMT、OOSE 等)
     ↓
1994:Rumbaugh 加入 Rational 的 Booch → 統一工作開始
     ↓
1995:UML 0.8 草案發布
     ↓
1996:OMG 發出標準建模語言的 RFP
     ↓
1997:OMG 採納 UML 1.1(11 月 14 日)
     ↓
2000:UML 1.3 正式發佈
     ↓
2003:UML 1.5 發佈;UML 2.0 超結構被接受

為何 UML 獲勝「方法之戰」

  • 整合了超過 50 種競爭性的物件導向方法為一種標準

  • 獲得主要產業參與者(IBM、Microsoft、Oracle、HP)的支持

  • 提供擴展機制以支援客製化

  • 成為物件導向建模的事實標準

⚠️ 批判性觀點:有人認為 UML 是「由委員會設計的怪物語言」,早期版本語義不精確。


🔹 類別與屬性

類別結構

UML 類別以最多三個區段的矩形來表示。

@startuml
class Student {
  firstName: String
  lastName: String
  email[0..1]: String
  encryptedPW: String
  + totalPoints(): Integer
  + setPassword(pw: String)
  + checkPW(pw: String): Boolean
}
@enduml

屬性宣告語法

[存取權限] 名稱[多重性]: 類型 [= 預設值] {屬性}

PlantUML 範例:

@startuml
class Student {
  + ProgramOfStudy[0..2]: String = "MIS"
  - encryptedPW: String {frozen}
  # internalID: Integer
  ~ packagePrivateData: String
}
@enduml

屬性範圍

  • 實例範圍 (預設): 每個物件都有其自身的值

  • 類別範圍 (靜態): 所有實例共享的單一值

@startuml
class Student {
  name: String
  {static} count: Integer
}
@enduml

UML 中的鍵 ⚠️

重要限制: UML 沒有內建的鍵概念。可使用範型或標記值作為替代方案。

@startuml
class Student {
  {pk} id: Integer
  {ak1} email: String
  - name: String
}
@enduml


🔹 關聯與關係

基本關聯與多重性

@startuml
class Exercise
class Chapter
Exercise "0..*" -- "1..1" Chapter : 屬於
@enduml

解釋: 每個練習僅屬於一個章節;一個章節可包含零個或多個練習。

角色名稱

除了(或除了)關聯名稱外,可在關聯端使用角色名稱:

@startuml
class Person
class Company
Person "0..*" --> "0..1" Company : 員工/雇主
@enduml

實現: 這人員 表格將有一個外鍵 僱主 參考 公司.

可導航性

使用箭頭指定遍歷方向:

@startuml
class 練習
class 章節
練習 "0..*" --> "1" 章節
@enduml

  • 箭頭表示高效遍歷方向

  • 在 OODB 中:僅以單向指針實現

  • 在 RDBMS 中:無論如何,連接都可雙向運作

具有 的集合類型{有序}

@startuml
class 章節
class 練習
章節 "1" -- "0..*" 練習 : {有序}
@enduml

  • {有序}: 維持順序(使用清單,而非集合)

  • 在 RDBMS 中的實現:新增順序編號屬性

練習 (
    id 主鍵,
    chapter_id 參考 章節,
    sort_no 整數,
    (chapter_id, sort_no) 唯一
)

限定詞

限定詞使用類似鍵的機制來劃分相關物件:

@startuml
class Chapter
class Exercise
Chapter "1" --> "0..1" Exercise : <<qualifier>> no: Integer
@enduml

含義:給定一個章節和練習編號,最多只會返回一個練習。

關聯類

當關聯具有屬性或操作時:

@startuml
class Student
class Exercise
class Solution {
  date: Date
  points: Integer
}
Student "0..*" -- "0..*" Exercise : has solved
Solution .. Student
Solution .. Exercise
@enduml

  • 一個 解答 物件對應每對(學生,練習)

  • 強制執行:同一學生不能為同一練習提交兩個解答

組合與聚合

特徵 組合(*--) 聚合(o--)
符號 黑色菱形 白色菱形
關係 整體-部分,強擁有 整體-部分,弱引用
生命週期 整體刪除時,零件也一併刪除 零件獨立
多重性 整體側為 1 或 0..1 任意
RDBMS 映射 ON DELETE CASCADE 標準外鍵
@startuml
class 章節
class 練習
章節 *-- "0..*" 練習 : 組成
章節 o-- "0..*" 練習 : 聚合
@enduml


🔹 操作與方法

操作宣告語法

@startuml
class 計算器 {
  + getTotal(學號: Integer, 包含額外: Boolean = true): Float {isQuery=true}
  + {static} getInstance(): 計算器
  + {constructor} Calculator(初始值: Float)
  - recalculate(): void
}
@enduml

參數規範:

[方向] 名稱: 類型 [= 預設值]
  • 方向:in(預設),outinout

  • 預設值可讓參數成為選擇性

特殊操作範疇

類型 目的
{isQuery=true} 確保不會修改狀態
{建構函數} 建立並初始化新的實例
{靜態} 類別層級操作,無隱含self

資料庫環境中的操作

文化衝突: 面向物件強調封裝;關聯式強調直接資料存取。

實作策略:

操作類型 RDBMS 實作
簡單屬性存取 直接 SELECT/UPDATE
衍生屬性(無參數) 資料庫 VIEW
衍生屬性(帶參數) 儲存程序或應用程式邏輯
複雜約束強制執行 觸發程序或應用程式程序

🔹 一般化與繼承

基本一般化

@startuml
class Person
class Student
class Professor
Person <|-- Student
Person <|-- Professor
@enduml

抽象類別與操作

@startuml
抽象類別 Account {
  - balance: Float
  + deposit(amount: Float): void
  + {抽象} withdraw(amount: Float): void
}
@enduml

一般化約束

@startuml
class Person
class Student
class Professor
class OtherPerson
Person <|-- Student : <<{互斥, 完整}>>
Person <|-- Professor : <<{互斥, 完整}>>
Person <|-- OtherPerson : <<{互斥, 完整}>>
@enduml

多重分類 / 鑑別器

@startuml
class Employee
class Staff
class Faculty
class HMO
class NonHMO
Employee <|-- Staff : <<類型>>
Employee <|-- Faculty : <<類型>>
Employee <|-- HMO : <<保險>>
Employee <|-- NonHMO : <<保險>>
@enduml

  • 鑑別器將互斥的特殊化分組

  • 物件在每個鑑別器維度上只能有一個值


🔹 擴展機制

UML 提供三種擴展機制:

1. 標記類型<< >>

透過建立模型元素的新「子類型」來擴展 UML 語義。

@startuml
class Customer <<實體>> {
  - id: Integer
  - name: String
}
class MathLibrary <<工具>> {
  + sin(x: Float): Float
  + cos(x: Float): Float
}
@enduml

2. 標籤值{鍵=值}

為模型元素新增自訂屬性。

@startuml
class Student {
  {author=sb, version=1.0, persistence=persistent}
  - id: Integer
}
@enduml

3. 約束{...}

使用自由格式文字、OCL 或預定的縮寫來新增語義限制。

@startuml
class Exercise {
  - no: Integer
  - points: Integer {value >= 0}
  {points <= maxPoints}
}
@enduml


🔹 用於資料庫設計的 UML:關鍵考量

將 UML 轉換為關聯式結構

UML 結構 關聯式實作
類別 資料表
屬性 欄位
主要鍵{pk} PRIMARY KEY 約束
關聯 (1:*) 在「多」端的外來鍵
關聯 (:) 連接/交集資料表
組合 外來鍵 +ON DELETE CASCADE
關聯類別 具有複合外鍵和屬性的表格
泛化 分離的表格(帶外鍵)或單一表格搭配類型鑑別器
{有序}關聯 新增序列欄位 + 唯一性約束
限定詞 複合鍵或索引欄位的一部分

關鍵差異:物件導向 vs. 關係型

面向 物件導向 關係型
身分識別 物件參考(代理) 主要鍵(業務或代理)
操作 設計的核心,封裝的 外部(SQL、程序)
封裝 私有屬性,公開介面 預設直接存取表格
繼承 原生語言支援 複雜的對應策略
關係 指標/參考 外鍵與連接

資料庫設計師的實務建議

  1. 明確地建模鍵: 使用 {pk}{ak1} 型別,因為 UML 缺乏原生金鑰支援

  2. 標記持久性: 使用 {persistent} 標記值,用於區分資料庫類別與暫時性應用程式類別

  3. 簡化操作: 將查詢操作對應至檢視;複雜操作對應至儲存程序

  4. 謹慎處理繼承: 根據查詢模式選擇對應策略

  5. 記錄約束: 使用 OCL 或明確文字約束來表示商業規則

  6. 審慎使用關聯類別: 僅在關係具有重要屬性時


🎯 快速參考速查表

PlantUML 類別圖符號摘要

@startuml
class <<型別>> 類別名稱 {
  {標記=值}
  [+/-/#/~] 名稱[多重性]: 類型 [= 值] {屬性}
  [+/-/#/~] 名稱(參數): 回傳值 {屬性}
}
@enduml

關聯符號

@startuml
類別A "多重性A" -- "多重性B" 類別B : 關聯名稱
類別A *-- 類別B  ' 組合
類別A o-- 類別B  ' 聚合
類別A --> 類別B  ' 可導航
@enduml

可見性符號

  • + 公開

  • - 私有

  • # 受保護

  • ~ 套件

常見屬性與約束

  • {靜態} / {isQuery=true} / {抽象}

  • {值 >= 0} / {互斥} / {有序} / {主鍵}


💡 最終想法: UML類別圖對於概念建模非常強大,但請記住它們主要是為軟體工程設計的。當使用UML進行資料庫設計時,應準備好擴展符號(使用樣式、標籤值、約束),以捕捉關係概念,例如鍵、正規化和宣告式約束,這些都不是UML物件導向基礎的原生功能。

本指南彙整自Stefan Brass所著《第6部分:UML類別圖》,哈雷大學,2003年。所有圖表均以PlantUML語法格式化,以確保與現代工具的相容性。

Leave a Reply