概述
- UML (Unified Modeling Language) 是用於說明、視覺化、構建和編寫物件導向軟體系統的統一建模語言
- 類別圖是用來描述系統中物件的類型及其之間的各種靜態關係
物件導向基本觀念
物件 (Object)
- 物件導向程式設計的主體是物件,它們合作完成系統運作
- 物件導向程式可視為多個具互動關係之物件的集合
類別 (Class) 與物件 (Object)
-
類別:抽象的模板,定義相同特徵的一群物件
- 不具備實際的值
- 定義屬性和方法
-
物件:由類別產生的具象實體
- 又稱實例 (instance)
- 具有實際的值
- 相同類別的物件具有相同特性,但屬性內容可能不同
屬性 (Attribute) 與方法 (Method)
- 屬性:定義類別的特徵,物件會有不同的屬性內容
- 方法:定義類別的行為,雖然演算法相同,但執行結果可能不同
UML 類別圖
類別表示法
基本類別
┌─────────────────┐
│ ClassName │
├─────────────────┤
│ -attribute1 │
│ #attribute2 │
│ +attribute3 │
├─────────────────┤
│ -method1() │
│ #method2() │
│ +method3() │
└─────────────────┘
抽象類別
抽象類別的名稱使用斜體表示,或在名稱上方加上 {abstract} 標記
┌─────────────────┐
│ «abstract» │
│ ClassName │ 或 斜體表示: ClassName
├─────────────────┤
│ -attribute1 │
│ #attribute2 │
├─────────────────┤
│ +method1() │
│ +abstract1() │ 抽象方法也用斜體表示
└─────────────────┘
介面 (Interface)
介面可以用兩種方式表示:
- 使用標準類別符號但加上 «interface» 標籤
┌─────────────────┐
│ «interface» │
│ InterfaceName │
├─────────────────┤
│ │
├─────────────────┤
│ +method1() │
│ +method2() │
└─────────────────┘
- 使用圓圈表示法 (Lollipop Notation),特別用於表示一個類別實作多個介面時
○ InterfaceName
│
┌────┼────────────┐
│ ClassName │
├─────────────────┤
│ │
└─────────────────┘
可見性符號
+: public#: protected-: private~: package (僅限於同一package)
靜態成員
- 靜態屬性或方法用底線標示,例如:
+staticMethod()
從 Use Cases 找出物件/類別
- 名詞/動詞分析:文字描述中的名詞可找出類別與屬性,動詞可找出操作
- 將屬性與操作放入合適類別中
- 設定類別間的關係
類別間的關係 (Relationship)
1. 相依 (Dependency) - “uses a”
- X使用Y:X呼叫Y的method
- 短期關係
- 表示法:虛線箭頭
X ---> Y - 範例程式碼:
class X {
void f1(Y y) {
// X 使用 Y 作為參數
y.foo();
}
void f2() {
// X 在方法中建立並使用 Y
Y y = new Y();
y.foo();
}
}另一個範例:
class Car {
private double weight;
public void addBaggageWeight(Baggage baggage) {
// Car 呼叫 Baggage 的方法,表示相依關係
weight += baggage.getWeight();
}
}2. 關聯 (Association) - “knows a”
- X熟識Y:X包含Y的reference
- 長期關係
- 表示法:實線箭頭
X ──→ Y - 範例程式碼:
class X {
private Y y; // X 保持對 Y 的引用
public X(Y y) {
this.y = y;
}
}另一個範例 (Book 和 Author 的關聯):
class Book {
private String name;
private Author[] authors; // 一對多的關聯
public Book(String name) {
this.name = name;
this.authors = new Author[10];
}
void addAuthor(Author author) {
// 實作新增作者的邏輯
}
void listAuthors() {
for(int i = 0; i < authors.length; i++) {
System.out.println(authors[i]);
}
}
}3. 組合 (Composition) - “has a”
- X包含Y,Y不可被其他物件包含
- X與Y生命週期一致:若刪除X,則Y隨之被刪除
- 表示法:實線+實心菱形
X ◆──→ Y - 範例程式碼:
class X {
private Y[] y; // 組合關係,Y由X建立和管理
public X() {
y = new Y[10]; // 在建構子中建立Y對象
// 當X被回收時,Y對象也會被回收
}
}另一個範例:
class Airplane {
private Bitmap bitmap; // Airplane和Bitmap形成組合關係
private int x, y;
void move() {
x += 10;
y += 20;
}
void draw() {
bitmap.draw(x, y);
}
}4. 聚合 (Aggregation) - “has a”
- X包含Y,但Y可被其他物件包含
- 當X消失,Y仍然存在
- 表示法:實線+空心菱形
X ◇──→ Y - 範例程式碼:
class Department {
private ArrayList<Employee> employees; // 聚合關係
// 部門通過引用Employee來建立關聯
public void addEmployee(Employee employee) {
employees.add(employee);
}
// 部門解散不會導致員工消失
public void disband() {
employees.clear();
}
}5. 繼承 (Inheritance) - “is a”
- X繼承自Y
- 表示法:實線+空心三角形
X ───▷ Y - 範例程式碼:
class Y {
// 父類別
}
class X extends Y {
// 子類別,繼承Y的屬性和方法
}6. 實作 (Implementation) - “can do”
- X實作Y的介面
- 表示法:虛線+空心三角形
X ---▷ Y - 範例程式碼:
interface Comparable {
int compareTo(Object obj);
}
class MyDate implements Comparable {
// 實作Comparable介面
public int compareTo(Object obj) {
// 實作比較邏輯
return 0;
}
}
class MyTime implements Comparable {
// 也實作Comparable介面
public int compareTo(Object obj) {
// 實作比較邏輯
return 0;
}
}其他重要概念
抽象類別 (Abstract Class)
- 無法產生物件,但可被繼承
- 通常用於表示概念性的分類
- 範例程式碼:
abstract class Vehicle {
// 抽象類別無法直接實例化
public abstract void turnLeft();
public abstract void turnRight();
}
class Bike extends Vehicle {
public void turnLeft() {
// 腳踏車的左轉實作
}
public void turnRight() {
// 腳踏車的右轉實作
}
}多型 (Polymorphism)
- 不同的物件可以有相同的方法名稱,但呈現出不同行為
- 是繼承可達成的重要效益
- 範例程式碼:
class Client {
double op1(Shape s) {
// 多型:根據實際的Shape類型調用不同的getArea()實作
double area = s.getArea();
return area;
}
}
abstract class Shape {
public abstract double getArea();
}
class Rectangle extends Shape {
private double length;
private double width;
public double getArea() {
return length * width;
}
}
class Circle extends Shape {
private double radius;
public double getArea() {
return Math.PI * radius * radius;
}
}實際建模步驟
- 識別所有類別
- 建立類別間的關係
- 設定屬性
- 設定方法
領域模型範例
以客戶訂單系統為例:
- 客戶有公司客戶與個人客戶兩種 (繼承關係)
- 客戶會下訂單買產品 (關聯關係)
- 訂單包含產品資訊 (組合關係)
Customer ────→ Order ◇────→ ProductInfo
△
│
├─── CorporateCustomer
│
└─── PersonalCustomer
類別圖與軟體設計的定位
- 從需求分析到程式碼的過程中,類別圖提供了從概念模型到實作的橋樑
- 在領域驅動設計 (DDD) 中扮演重要角色
- 可與其他UML圖形搭配使用,如使用案例圖、活動圖、循序圖等