📘 引言:從孤立元件到連結系統——類圖的演進
在軟體開發的世界中,類圖不僅僅是靜態的圖示——它們是隨著所代表系統一同演變的活躍藍圖。在開發的每個階段,從最初的規格需求到發布後的維護,類圖的細節層次、結構與設計意圖都會產生顯著變化。然而,一個常見的陷阱始終存在:孤立的元件.
考慮典型的付款處理器類——CreditCardProcessor, PayPalProcessor,以及StripeProcessor——通常在類圖中被建模為獨立且彼此脫節的實體。雖然這在早期設計階段可能足夠,但卻暴露出更根本的問題:整合與行為清晰度的缺乏。這些類別彼此孤立,缺乏明確的選擇、設定或執行時期彈性的機制。結果導致設計僵化、難以擴展且難以測試。
本文探討類圖應如何演進於開發各階段——從高階概念模型到詳細且可執行的設計——以及如何策略性連結元件之間的策略性連結,能將零散的系統轉化為整合且可擴展的架構。我們將聚焦於一個實際案例:付款處理子系統——並展示如何應用策略模式, 工廠模式,以及依賴注入,來彌補孤立類別與真正動態、可維護系統之間的差距。
透過PlantUML 圖表以及實用的設計洞見,你將學會如何:
- 超越靜態類別關係。
- 模擬現實世界的行為與執行時期動態。
- 設計靈活、可擴展且易於演進的系統。
到最後,你會發現一個連接良好的類圖不僅僅是文檔工具——它是一種你的軟體應如何運作的視野.
類圖是用於建模物件導向系統的最強大 UML 工具之一。它們的細節層級會根據開發階段而有顯著差異。本指南將帶你走過四個關鍵階段的軟體開發過程,並展示類圖如何相應地演進。
🧩 1. 階段 1:需求與概念設計(早期階段)
🎯 目的:
- 捕捉高階領域概念。
- 識別關鍵實體及其關係。
- 促進利益相關者與開發人員之間的溝通。
🔍 特徵:
- 著重於領域實體與關係.
- 無方法或屬性(或極少)。
- 使用泛化, 關聯, 聚合,以及 組成.
- 避免實現細節(例如存取修飾符、資料類型)。
📌 範例:電子商務系統(概念層級)
@startuml
' 概念類別圖 - 第一階段:需求
class 客戶 {
+姓名:字串
+電子郵件:字串
}
class 產品 {
+名稱:字串
+價格:十進位
}
class 訂單 {
+訂購日期:日期
+狀態:字串
}
客戶 "1" -- "0..*" 訂單 : 下單
訂單 "1" -- "1..*" 產品 : 包含
產品 "1" -- "0..*" 訂單 : 售出於
note right of 客戶
代表購買產品的使用者
end note
note right of 產品
可實體或數位的銷售項目
end note
note right of 訂單
交易紀錄
end note
@enduml
✅ 使用案例:向利害關係人展示,優化領域模型,並與業務分析師驗證。
🧱 2. 第二階段:分析與高階設計(中期)
🎯 目的:
- 將領域模型進一步細化為更結構化的設計。
- 引入 屬性, 基本操作,以及 關聯.
- 開始識別 介面, 抽象類別,以及 設計模式.
🔍 特徵:
- 新增 屬性 和 操作 (使用最少的類型)。
- 使用 抽象類別 和 介面.
- 引入 多重性 和 可導航性.
- 開始思考 責任 和 內聚性.
📌 範例:電子商務系統(分析層級)
@startuml
' 高階類別圖 - 第二階段:分析
@startuml
' 高階類別圖 - 第二階段:分析
抽象類別 Order {
- orderID: 字串
- orderDate: 日期
- status: 字串
+calculateTotal(): 十進位
+validate(): 布林
+save(): 無回傳值
}
class Customer {
- customerID: 字串
- name: 字串
- email: 字串
+addOrder(order: Order): 無回傳值
+getOrders(): List<Order>
}
class Product {
- productID: 字串
- name: 字串
- price: 十進位
- stockQuantity: 整數
+isInStock(): 布林
+updateStock(amount: 整數): 無回傳值
}
class OrderItem {
- quantity: 整數
- unitPrice: 十進位
+getSubtotal(): 十進位
}
Customer "1" -- "0..*" Order : 下單
Order "1" -- "1..*" OrderItem : 包含
OrderItem "1" -- "1" Product : 參考
Product "1" -- "0..*" OrderItem : 出現在
介面 PaymentProcessor {
+processPayment(amount: 十進位): 布林
}
Order "1" -- "1" PaymentProcessor : 使用
@enduml
✅ 使用案例:設計審查、團隊協調、初步架構決策。
🔧 3. 第三階段:詳細設計與實現(後期階段)
🎯 目的:
- 為編碼做準備。
- 定義 精確的屬性, 方法, 資料類型, 存取修飾詞.
- 包含 約束, 相依性, 關聯,以及 組合.
- 使用 設計模式 (例如:工廠模式、策略模式、單例模式)。
🔍 特徵:
- 完整的方法簽章與傳回類型。
- 使用 存取修飾詞 (
+,-,#). - 依賴關係, 繼承, 介面均已被完整定義。
- 可能包含約束條件(例如,
<<約束條件>>).
📌 範例:電子商務系統(詳細設計)
@startuml
' 詳細類圖 - 第三階段:實作
@startuml
' 詳細類圖 - 第三階段:實作
class Customer {
- customerID: 字串
- name: 字串
- email: 字串
- address: 字串
+addOrder(order: Order): 無
+getOrders(): List<Order>
+validateEmail(): 布林
}
class Order {
- orderID: 字串
- orderDate: 日期
- status: OrderStatus
- total: 十進位
+calculateTotal(): 十進位
+validate(): 布林
+save(): 無
+cancel(): 無
}
class OrderItem {
- quantity: 整數
- unitPrice: 十進位
+getSubtotal(): 十進位
}
class Product {
- productID: 字串
- name: 字串
- price: 十進位
- stockQuantity: 整數
+isInStock(): 布林
+updateStock(amount: 整數): 無
+getPrice(): 十進位
}
class PaymentProcessor {
+processPayment(amount: 十進位): 布林
}
class CreditCardProcessor {
+processPayment(amount: 十進位): 布林
}
class Payment {
- paymentID: 字串
- amount: 十進位
- method: 字串
- timestamp: 日期
+confirm(): 布林
}
' 繼承
Customer <|-- PremiumCustomer
' 介面
PaymentProcessor <|-- CreditCardProcessor
PaymentProcessor <|-- PayPalProcessor
' 關聯
Customer "1" -- "0..*" Order : 下單
Order "1" -- "1..*" OrderItem : 包含
OrderItem "1" -- "1" Product : 參考
Order "1" -- "1" Payment : 擁有
PaymentProcessor "1" -- "1" Payment : 處理
' 約束條件
note right of Order
狀態:[待處理, 已確認, 已出貨, 已取消]
end note
note right of Product
庫存必須大於 0 才能銷售
end note
@enduml
✅ 使用案例:開發者交接、程式碼產生、設計文件記錄。
🛠️ 4. 第四階段:維護與演進(發行後)
🎯 目的:
- 反映現實世界的變更系統中的變更。
- 文件重構, 已棄用, 新功能.
- 支援技術負債追蹤和系統理解.
🔍 特性:
- 可能包含已棄用類別/方法。
- 顯示新類別, 重新命名的元件, 已移除的元件.
- 使用範疇 (
<<已棄用>>,<<單例>>,<<工廠>>). - 通常 簡化 以提高可讀性。
📌 範例:電子商務系統(維護階段)
@startuml
' 重新設計的支付系統:策略 + 工廠模式
' 介面
class PaymentProcessor {
+processPayment(amount: Decimal): Boolean
}
' 具體策略
class CreditCardProcessor {
+processPayment(amount: Decimal): Boolean
}
class PayPalProcessor {
+processPayment(amount: Decimal): Boolean
}
class StripeProcessor {
+processPayment(amount: Decimal): Boolean
}
' 工廠模式
class PaymentProcessorFactory {
+createProcessor(type: String): PaymentProcessor
+getAvailableTypes(): List<String>
}
' 使用策略的服務
class OrderService {
- processor: PaymentProcessor
+createOrder(customer: Customer, items: List<OrderItem>): Order
+setPaymentProcessor(processor: PaymentProcessor): void
}
' 支付實體
class Payment {
- paymentID: String
- amount: Decimal
- method: String
- timestamp: Date
+confirm(): Boolean
}
' 客戶與訂單(簡化)
class Customer {
- customerID: String
- name: String
- email: String
+addOrder(order: Order): void
+getOrders(): List<Order>
}
class Order {
- orderID: String
- orderDate: Date
- status: OrderStatus
- total: Decimal
+calculateTotal(): Decimal
+validate(): Boolean
+save(): void
+cancel(): void
}
' 標籤以增加清晰度
PaymentProcessor <<interface>>
CreditCardProcessor <<strategy>>
PayPalProcessor <<strategy>>
StripeProcessor <<strategy>>
PaymentProcessorFactory <<factory>>
OrderService <<service>>
' 繼承:策略模式
CreditCardProcessor <|-- PaymentProcessor
PayPalProcessor <|-- PaymentProcessor
StripeProcessor <|-- PaymentProcessor
' 工廠建立處理器
PaymentProcessorFactory "1" -- "1" PaymentProcessor : 建立
' OrderService 使用處理器(依賴注入)
OrderService "1" -- "1" PaymentProcessor : 使用
' OrderService 使用工廠來設定處理器
OrderService "1" -- "1" PaymentProcessorFactory : 透過配置
' 支付依賴處理器
Payment "1" -- "1" PaymentProcessor : 使用
' 關聯關係
Customer "1" -- "0..*" Order : 下單
Order "1" -- "1..*" OrderItem : 包含
OrderItem "1" -- "1" Product : 參考
Order "1" -- "1" Payment : 擁有
' 約束
note right of Order
狀態:[待處理, 已確認, 已出貨, 已取消]
end note
note right of Payment
方式:"CreditCard", "PayPal", "Stripe"
end note
note right of PaymentProcessorFactory
支援的類型:"CreditCard", "PayPal", "Stripe"
可擴展而不需修改 OrderService
end note
@enduml ✅ 使用案例:新開發人員入職、系統重構、審計追蹤。
🔄 總結:類圖的演進
| 階段 | 重點 | 細節層級 | 關鍵元素 |
|---|---|---|---|
| 1. 需求 | 領域概念 | 高階 | 實體、關聯 |
| 2. 分析 | 系統結構 | 中等 | 屬性、操作、介面 |
| 3. 實作 | 程式碼就緒 | 高 | 類型、存取修飾符、設計模式 |
| 4. 維護 | 系統演進 | 適應性 | 範疇、棄用、簡化 |
🛠️ 使用 PlantUML 的提示
- 使用
@startuml和@enduml來包裝圖表。 - 使用
<<範疇>>用於設計模式或元數據。 - 使用
note right of用於文件記錄。 - 使用
+,-,#用於可見性(公開,私有,保護). - 使用
<<介面>>,<<抽象>>,<<單例>>為清晰起見。 - 透過 PlantUML Online 或 IDE 插件(VS Code、IntelliJ)。
📚 最後想法
類圖是 非靜態 — 它們 隨著專案演進。務必策略性地使用它們:
- 早期:與非技術利益相關者溝通。
- 中期:讓開發人員在架構上達成共識。
- 晚期:引導實作與程式碼品質。
- 發行後:維持系統知識。
✅ 專業提示:將你的 PlantUML 檔案與程式碼一同進行版本控制——它們是活文件!
✅ 結論:設計的不只是類別,更是系統
類圖不只是圖表——它們是意圖的地圖, 合作的藍圖,以及建築演進的活體紀錄。正如我們所見,它們的價值不在於最初的形態,而在於它們如何適應在開發生命週期中不斷演變——從需求的高階抽象,到後期設計中精確且可執行的模型。
從孤立的處理器類別到一個相互連結、以策略為導向的系統的演進,揭示了一個根本的事實:優秀的設計不僅在於定義組件——更在於定義它們如何協同運作。當CreditCardProcessor, PayPalProcessor,以及StripeProcessor被視為可互換的策略——由工廠協調並注入服務中——圖表便不再只是靜態的快照。它變成了一個彈性動態模型、可擴展性與可維護性。
透過使用如策略, 工廠,以及依賴注入,我們將孤立的類轉化為一個整合且可擴展的生態系統。這不僅僅是為了更好的圖表——更是為了打造更好的軟體。它讓團隊能夠:
- 在不觸碰現有程式碼的情況下新增付款方式。
- 獨立測試行為。
- 即使在發佈多年後,也能有信心地演進系統。
最終,最具威力的類別圖並非那些詳細展示每個欄位與方法的圖——而是那些講述一個故事:一個關於合作、適應力與前瞻設計的故事。
當你繪製下一個類別圖時,請問問自己:
我的類別只是被定義了嗎——還是它們彼此相連?
它們是孤立的嗎——還是屬於一個能夠成長的系統的一部分?
因為最終,最好的類別圖不僅僅描述系統是什麼——它們激發系統應該如何發展.











