# 第4章 类图与对象图

> **考试重要度**：★★★★★  
> **核心内容**：类与对象的识别、六大类关系、抽象类与接口、边界类/控制类/实体类

---

## 📢 从生活中理解类和对象

💬 **类 = 模板，对象 = 具体的东西。**

| 概念 | 生活例子 | 代码例子 |
|------|----------|----------|
| **类** | "汽车"这个类别 | `class Car` |
| **对象** | 你家楼下停的那辆红色宝马 | `Car myCar = new Car()` |
| **属性** | 颜色、车牌号、排量 | `color`, `plateNumber` |
| **操作** | 启动、加速、刹车 | `start()`, `accelerate()` |

> 例：银行的"账户"类有属性（姓名、密码、余额）和操作（查询余额、存款、取款）。张三的账户就是一个具体对象，余额是5000元。

---

## 💡 一、类的三格表示法

```
┌──────────────────────┐
│   类名               │  ← 第一格：类名
├──────────────────────┤
│   -name: String      │  ← 第二格：属性
│   -age: int          │
│   +count: int        │
├──────────────────────┤
│   +getName(): String │  ← 第三格：操作（方法）
│   +setAge(a: int)    │
└──────────────────────┘
```

### 属性语法

```
[可见性] 属性名 [:类型] [=初始值] [{约束}]
```

### 可见性符号

| 符号 | 名称 | 含义 |
|------|------|------|
| `+` | Public（公有） | 谁都能访问 |
| `-` | Private（私有） | 只能类内部访问 |
| `#` | Protected（受保护） | 类内部+子类能访问 |

---

## ✍️ 边学边练（一）

**题目**：银行账户类Account有属性：账号(私有)、密码(私有)、余额(私有)、利率(公有)。请用UML类图的三格表示法写出。

**答案：**
```
┌──────────────────────┐
│      Account         │
├──────────────────────┤
│  -accountNo: String  │
│  -password: String   │
│  -balance: double    │
│  +interestRate: float│
├──────────────────────┤
│  +getBalance():double│
│  +deposit(amt)       │
│  +withdraw(amt)      │
└──────────────────────┘
```

---

## 💡 二、类之间的六大关系（重中之重！必考！）

### 1. 关联关系（Association）—— "认识/拥有"

> **含义**：一个类的属性类型是另一个类。这是最基础的关系。

💬 **比喻**：员工"属于"某个部门——Employee类中有一个Department类型的属性。

**关联关系的子类型**：

| 子类型 | 说明 | 生存期 | 画法 |
|--------|------|--------|------|
| **普通关联** | 平等关系 | 各自独立 | 实线 |
| **聚合（Aggregation）** | 整体-部分，弱关系 | 部分可独立存在 | 空心菱形 |
| **组合（Composition）** | 整体-部分，强关系 | 部分随整体消亡 | 实心菱形 |

💬 **聚合 vs 组合**：
- 聚合：学校由学生组成，学校解散了，**学生还在**。
- 组合：汽车由发动机组成，汽车报废了，**发动机也没意义了**。

### 2. 依赖关系（Dependency）—— "临时使用"

> **含义**：一个类的方法的参数/返回值/局部变量用了另一个类。

💬 **比喻**：你去商店买东西——你跟商店的关系只在买东西那一刻存在，买完就没关系了。

### 3. 泛化关系（Generalization）—— "是……的一种"

> **含义**：子类继承父类的属性和方法。

💬 **比喻**：狗是动物的一种——狗继承了动物的所有特征，还有自己特有的"汪汪叫"。

### 4. 实现关系（Realization）—— "履行接口约定"

> **含义**：类实现了接口中定义的所有方法。

### 关联 vs 依赖 对比

| 维度 | 关联 | 依赖 |
|------|------|------|
| **强度** | 强，长期稳定 | 弱，临时短暂 |
| **代码体现** | 属性类型是另一个类 | 方法参数/局部变量用了另一个类 |
| **生命周期** | 对象存在就有关系 | 方法调用结束关系就结束 |
| **画法** | 实线 | 虚线箭头 |

---

## ✍️ 边学边练（二）

**题目**：判断以下场景属于什么关系。

1. 飞机由机翼、发动机、机身组成。（飞机-机翼）
2. 医生在医院工作。（医生-医院）
3. 学生是人。（学生-人）
4. 程序员写代码时用到开发工具。（程序员-开发工具）

**答案：**
1. **组合关系**（实心菱形）—— 机翼不能脱离飞机独立存在
2. **关联关系**（普通关联）—— 医生有"所属医院"这个属性
3. **泛化关系**（继承）—— 学生是人的子类
4. **依赖关系**（虚线箭头）—— 程序员"写代码"这个方法用到了开发工具，但不是长期持有

⚠️ **易错点**：聚合和组合都表示"整体-部分"，区别在于部分能否独立存在。能独立=聚合，不能独立=组合。

---

## 💡 三、关联关系的重要概念

### 多重性

| 表示法 | 含义 |
|--------|------|
| `1` | 恰好1个 |
| `0..1` | 0个或1个 |
| `0..*` 或 `*` | 0个或多个 |
| `1..*` | 至少1个 |
| `n..m` | n到m个 |

> 例：一个学生选**0..\***门课，一门课被**1..\***个学生选。

### 关联类

> 当一个属性放在哪个类都不合适时，就用关联类。

💬 例：员工和公司之间有个"合同"——合同有"工资"属性。工资既不是员工的固有属性（换公司会变），也不是公司的固有属性。所以"合同"是一个关联类。

### 限定关联

> 用限定符把多对多变成一对多，提高查询效率。

💬 例：一个人可以在多家银行开户（多对多）。但如果限定"在某家银行"，就变成一对多了。

---

## 💡 四、抽象类 vs 接口

| 维度 | 抽象类 | 接口 |
|------|--------|------|
| **属性** | 可以有 | 不能有 |
| **方法实现** | 部分方法有实现 | 所有方法都没有实现 |
| **关系** | 子类继承（泛化） | 类实现（实现关系） |
| **多重性** | 只能继承一个 | 可以实现多个 |
| **关键词** | `abstract class` | `interface` |

💬 **比喻**：抽象类像"半成品家具"（有些部分做好了，有些需要你自己完成）；接口像"插座标准"（只规定了插孔形状和电压，具体怎么发电不管）。

---

## 💡 五、版型：边界类、控制类、实体类

这是MVC模式的UML体现，期中考试经常考！

| 版型                     | 职责     | 常见形式      | 对应MVC      |
| ---------------------- | ------ | --------- | ---------- |
| **边界类** `<<boundary>>` | 与外界交互  | 窗口、对话框、报表 | View       |
| **控制类** `<<control>>`  | 协调业务逻辑 | 处理业务规则    | Controller |
| **实体类** `<<entity>>`   | 持久化数据  | 数据库表对应的类  | Model      |

🔑 **协作关系**：边界类接收用户输入 → 控制类处理业务逻辑 → 实体类存取数据。

---

## 📌 附录：类图常用画图符号速查

> 这一节把类图中所有的关系符号、接口、抽象类、版型、对象图等所有画图元素用字符画列出来，画类图时直接照搬即可。

### 1. 关联关系（Association）—— 实线（可带多重性）

**普通关联**（双向带多重性）：

```
  ┌────────┐  1            0..*  ┌────────┐
  │  老师   │ ────────────────── │  学生   │
  └────────┘                     └────────┘
```

**自关联**（一个类关联到自己）：

```
              ┌────────┐
              │  员工   │
              │        │
              │  领导  │◀──┐
              └────────┘   │
                     │     │
                     └─────┘
```

### 2. 聚合关系（Aggregation）—— 实线 + 空心菱形 ◇

> 部分可脱离整体独立存在。

```
              ◇
  ┌────────┐                ┌────────┐
  │  班级   │ ───────────── │  学生   │
  └────────┘                └────────┘
   (整体)                   (部分，可独立)

💬 学校没了，学生还在 —— 所以是空心菱形
```

### 3. 组合关系（Composition）—— 实线 + 实心菱形 ◆

> 部分不能脱离整体独立存在。

```
              ◆
  ┌────────┐                ┌────────┐
  │  汽车   │ ───────────── │  发动机 │
  └────────┘                └────────┘
   (整体)                   (部分，离不开整体)

💬 汽车报废了，发动机也没意义了 —— 所以是实心菱形
```

### 4. 依赖关系（Dependency）—— 虚线 + 开放箭头

```
  ┌────────┐                ┌────────┐
  │  司机   │ ─ ─ ─ ─ ─ ─ ─⇨ │  汽车   │
  └────────┘                └────────┘
   (使用者)                  (被使用者)
   (虚线 + 开放箭头)
```

### 5. 泛化关系（Generalization）—— 实线 + 空心三角

**方向**：子类 → 父类（空心三角指向父类）。

```
                            ▷
  ┌────────┐                ┌────────┐
  │   狗    │ ───────────── │  动物  │
  └────────┘                └────────┘
   (子类)                   (父类)
```

### 6. 实现关系（Realization）—— 虚线 + 空心三角

**方向**：实现类 → 接口（空心三角指向接口）。

```
                            ▷
  ┌────────┐                ┌──────────────┐
  │   鸟    │ ─ ─ ─ ─ ─ ─ ─ │<<interface>>│
  └────────┘                │    飞行      │
   (实现类)                 └──────────────┘
                              (接口)
```

### 7. 接口的两种画法

**普通矩形画法**（在类图中更常见）：

```
  ┌──────────────────┐
  │  <<interface>>   │   ← 关键字标识
  │      飞行         │   ← 接口名
  ├──────────────────┤
  │ +起飞(): void    │   ← 只有声明，没有实现
  │ +降落(): void    │
  └──────────────────┘
```

**棒棒糖表示法**（简化版，常在组件图中使用）：

```
  ┌────────┐                    ┌────────┐
  │  鸟    │●─ ─ ─ ─ ─ ─ ─ ─ ─ ┤ 飞行  │  (棒棒糖+连接线)
  └────────┘                    └────────┘
  (实现类)            (接口)
```

### 8. 抽象类与抽象方法

> **画法**：抽象类**类名用斜体**、抽象方法**方法名用斜体**。在字符画里用 `<<abstract>>` 标识或加文字说明。

```
  ┌────────────┐
  │ 动物       │   ← 实际画图时类名用斜体
  ├────────────┤
  │            │
  ├────────────┤
  │ 移动()     │   ← 实际画图时方法名用斜体
  │ 叫()       │
  └────────────┘
  
  {abstract}     ← 标注方式（实际画图用斜体）
```

### 9. 版型（Stereotype）的画法

**边界类**：

```
  ┌────────────────┐
  │  <<boundary>>  │   ← 写在类名上方
  │    登录页面     │
  ├────────────────┤
  │  -用户名:String │
  │  -密码:String  │
  ├────────────────┤
  │  +提交():void │
  └────────────────┘
```

**控制类**：

```
  ┌────────────────┐
  │  <<control>>   │
  │   订单处理     │
  ├────────────────┤
  │                │
  ├────────────────┤
  │  +处理订单()   │
  │  +检查库存()   │
  └────────────────┘
```

**实体类**：

```
  ┌────────────────┐
  │  <<entity>>    │
  │      订单      │
  ├────────────────┤
  │  -订单号:String│
  │  -金额:double │
  ├────────────────┤
  │  +保存()      │
  │  +查询()      │
  └────────────────┘
```

### 10. 对象图的画法

> 对象名格式：`对象名:类名`（对象名和类名下加**下划线**），属性有具体值。

```
  ┌─────────────────┐
  │   张三:员工      │   ← 对象名:类名，下划线
  ├─────────────────┤
  │ 员工号 = "E001" │   ← 属性=值
  │ 姓名 = "张三"   │
  │ 年龄 = 28       │
  └─────────────────┘
```

**对象图与类图对比**：

```
  类图（描述规则）            对象图（描述实例）

  ┌──────────┐               ┌────────────────┐
  │   员工   │               │  张三:员工      │
  ├──────────┤               ├────────────────┤
  │ -员工号  │               │ 员工号="E001"  │
  │ -姓名    │      ──>       │ 姓名="张三"    │
  │ -年龄    │               │ 年龄=28        │
  ├──────────┤               └────────────────┘
  │ +查询()  │
  └──────────┘
```

### 11. 关联类的画法

> 关联类挂在关联线中间，用虚线连到关联线上。

```
  ┌────────┐                  ┌────────┐
  │  员工   │ ─ ─ ─ ─ ─ ─ ─ │  公司   │
  └────────┘    │            └────────┘
                │
           ┌────────┐
           │  合同   │   ← 关联类（虚线连到关联线上）
           ├────────┤
           │ -工资  │
           │ -合同期│
           └────────┘
```

🔑 **一句话记忆口诀**：实线实箭是关联，空心菱形是聚合，实心菱形是组合，虚线开放箭头是依赖；实线空三角是泛化（继承），虚线空三角是实现（接口）。

---

## ✍️ 边学边练（三）

**题目**：在线购物系统中，"用户"通过"购物页面"下单，系统"订单处理"模块检查库存后，更新"订单"数据和"库存"数据。请指出各属于哪种版型。

**答案：**
- 购物页面 → **边界类**（与用户交互）
- 订单处理模块 → **控制类**（协调业务逻辑）
- 订单、库存 → **实体类**（持久化的数据）

完整流程：边界类("购物页面") → 控制类("订单处理") → 实体类("订单""库存")

---

## 💡 六、对象图

> **对象图 = 类图的"截图"**。类图描述通用规则，对象图描述某一时刻的具体情况。

| 类图 | 对象图 |
|------|--------|
| 三个格子（类名+属性+操作） | 两个格子（对象名:类名 + 属性值） |
| 描述所有可能的情况 | 描述某一个时刻的快照 |
| 属性定义特征（如"姓名: String"） | 属性有具体值（如"姓名 = 张三"） |

💬 **比喻**：类图像"菜单"（描述菜的做法），对象图像"上桌的菜"（一份具体的菜）。

---

## 📝 章末自测

**1. 填空题**
- 聚合关系中，整体不存在了，部分（ ___ ）存在。（能/不能）
- 组合关系中，整体不存在了，部分（ ___ ）存在。（能/不能）
- 边界类、控制类、实体类分别对应MVC中的（ _____ ）、（ _____ ）、（ ___ ）

**2. 判断题**
- ( ) 依赖关系比关联关系更弱
- ( ) 接口可以有属性
- ( ) 抽象类可以被实例化
- ( ) 对象图是类图的实例
- ( ) 一个类只能继承一个抽象类，但可以实现多个接口

**3. 分析题**
- 职工类Employee包含属性empcode、name、address、birthday。Address类包含houseNumber、streetNumber、city、zipcode。分析两个类之间的关系。

**答案：**
**填空题**：能、不能、View、Controller、Model

**判断题**：✅ ❌(接口无属性) ❌(抽象类不能实例化) ✅ ✅

**分析题**：**关联关系**。因为Employee类中有一个属性address，其类型是Address类。这是一个长期稳定的结构关系。多重性：Employee端1，Address端0..*（一个地址可以被多个员工使用）。

---
> 🔗 上一篇：[第3章 用例图](第03章-用例图.md) | 下一篇：[第5章 顺序图与协作图](第05章-顺序图与协作图.md)
