11.3.3 例题3:通信图与类图
通信图与类图组合题的关键是互相补证:通信图对象名能提示类名,通信图消息能提示方法名;反过来,类图中的方法也能填回通信图缺失消息。
课程例题是高校图书馆借书系统,题目给出“借书”用例规约、部分类图和通信图,并额外考察设计模式。
通信图与类图的互证关系
通信图里的对象常写成:
text
对象名:类名冒号前是对象名,冒号后是类名。因此通信图中冒号后的英文词,经常可以直接填到类图的类名空位。
消息箭头的规则也很重要:
| 通信图信息 | 类图含义 |
|---|---|
A 向 B 发送消息 m() | m() 通常是 B 所属类的方法 |
冒号后出现 Book | 类图中可能有 Book 类 |
| 消息名在类图方法栏出现 | 可填回通信图缺失消息 |
| 消息编号 1、2、3 | 表示调用顺序 |
课程反复强调:箭头指向的是“消息所属对象”,另一侧是调用者。不要把方法误填到发起者类中。
借书用例的流程提取
题干中的“借书”用例规约大致是:
- 输入读者 ID。
- 确认读者能否借阅,并记录读者 ID。
- 输入图书 ID。
- 确认图书能否借阅,计算归还时间。
- 生成借阅记录。
- 通知读者归还时间。
- 重复图书输入和检查,直到读者完成借阅。
备选事件流:
- 如果读者不能借阅,告知原因,用例结束。
- 如果图书不能借阅,告知原因,回到输入图书 ID。
这些步骤会变成通信图中的消息,也会变成类图中的方法。
先找类,再找方法
课程建议:先找类名,再根据类找方法,思路更直接。
| 线索 | 推断 |
|---|---|
通信图对象 b:Book 或方法参数 bookID | 类图中应有 Book |
| 题干出现读者 ID 和读者身份 | 类图中应有 Reader/读者类 |
方法 checkOut(bookID) 指向某对象 | 该对象所属类包含该方法 |
| 类图中某类只有一个候选方法 | 可直接填通信图缺失消息 |
如果题目要求用英文词汇,要优先使用题目中给出的英文。
消息归属示意
mermaid
flowchart LR
Session["session:CheckoutSession"] -- "1: checkOut(bookID)" --> Book["book:Book"]
Book -- "2: calculateDueDate()" --> Session这里 checkOut(bookID) 的箭头指向 Book,所以该方法应属于 Book 或图中被指向对象对应的类;session 是调用者。
在真实题目中,如果多个消息名相近,要结合参数判断。例如同样叫 checkOut,带 bookID 的可能对应图书,带日期参数的可能对应归还日期计算或借阅记录。
借阅规则为什么适合策略模式
题目最后问:根据不同制度判断是否能借阅,制度可能不断扩充,运行时还要调整使用哪些制度,该用什么设计模式?
答案是策略模式。
理由:
| 题干线索 | 策略模式对应解释 |
|---|---|
| 借阅制度可能扩充 | 新增策略类 |
| 根据实际情况调整使用哪些制度 | 运行时切换策略 |
| 判断是否能借阅是一类规则/算法 | 将算法封装成类 |
mermaid
classDiagram
class BorrowPolicy {
+canBorrow(reader, book)
}
class TeacherPolicy
class StudentPolicy
class OverduePolicy
class BorrowService {
-BorrowPolicy policy
+borrow()
}
BorrowPolicy <|.. TeacherPolicy
BorrowPolicy <|.. StudentPolicy
BorrowPolicy <|.. OverduePolicy
BorrowService --> BorrowPolicy策略模式的标准表达是:定义一系列算法,把它们分别封装起来,并使它们可以互相替换。这里“制度”就是算法。
通信图题的完整解题流程
- 读问题,确定要填类名、方法名还是设计模式。
- 在通信图中找
对象名:类名,先填类名。 - 在类图方法栏中找候选方法。
- 看通信图消息箭头,箭头指向谁,方法就属于谁。
- 按消息编号确认调用顺序。
- 如果题目有扩展问设计模式,回到场景关键词判断。
例题
通信图主要强调:
通信图中消息 `m()` 从 A 指向 B,通常 `m()` 方法属于:
借阅制度可能不断扩充,并且可根据实际运行情况调整使用哪种制度,适合使用:
自查要点
- 通信图中冒号前后分别表示什么?
- 为什么消息箭头指向方通常提供对应方法?
- 类图和通信图如何互相补空?
- 借阅制度扩展为什么不是状态模式,而是策略模式?