Skip to content
难度基础(★)
建议时长45分钟

10.4.3 UML中的关系

UML 的关系是下午建模题的“语法”。如果关系方向看错,类名、用例名往往也会填错。

课程里重点讲两大块:类图中的关系和用例图中的关系。类图关系偏“结构”,用例图关系偏“功能复用、扩展、抽象”。

类图中的基本关系

关系含义常见图形符号箭头方向判断关键词
关联对象之间存在结构性连接实线可无箭头,也可表示导航方向知道、拥有、对应、属于
依赖一个事物的变化会影响另一个事物虚线箭头使用方指向被依赖方使用、调用、作为参数、临时访问
泛化一般与特殊,继承关系实线 + 空心三角子类指向父类is-a、是一种、父类/子类
实现类实现接口虚线 + 空心三角实现类指向接口implements、实现接口
聚合弱整体-部分,部分可独立存在空心菱形菱形在整体一侧整体-部分,生命周期不同
组合强整体-部分,部分依附整体实心菱形菱形在整体一侧强拥有,生命周期相同或强依赖

关系强弱可以粗略理解为:依赖 < 关联 < 聚合 < 组合。泛化和实现不是强弱链条上的“拥有关系”,它们表达类型抽象。

关联关系:一条线不只是“一条线”

关联描述对象之间的连接。它可以标注多重度,也可以标注角色。

mermaid
classDiagram
  class Teacher
  class Course
  Teacher "1" --> "0..*" Course : teaches
  Teacher "0..1" --> "0..*" Course : audits

同两个类之间可以有多个关联,只要它们由不同角色区分。课程中特别提醒:多个关联不一定要合并,也不能理解为“两个类之间只能有一条关联”。

常见多重度含义:

多重度含义
1恰好一个
0..1零个或一个
0..*零个或多个
1..*一个或多个
m..n至少 m 个,至多 n 个

依赖、泛化、实现的箭头方向

箭头方向是考试常见坑。

mermaid
classDiagram
  class ReportService
  class PdfExporter
  class Animal
  class Dog
  class PaymentGateway {
    <<interface>>
  }
  class AlipayGateway

  ReportService ..> PdfExporter : depends on
  Dog --|> Animal : generalization
  AlipayGateway ..|> PaymentGateway : realization

依赖:使用方指向被使用方。例如 ReportService 临时调用 PdfExporter,则服务依赖导出器。

泛化:子类指向父类。Dog 是一种 Animal,所以箭头指向更抽象、更一般的 Animal

实现:实现类指向接口。接口像契约,实现类履行契约。

聚合与组合:区别在生命周期

聚合和组合都是整体-部分关系,关键差异不是“有没有包含”,而是部分对象能否脱离整体继续有意义地存在。

对比项聚合组合
符号空心菱形实心菱形
关系强度较弱很强
生命周期整体消失,部分仍可独立存在整体消失,部分通常一起消失或失去意义
课程例子班级与学生公司与财务部
建模判断“属于某个集合,但能离开集合存在”“部分由整体强拥有,不能自然脱离整体”
mermaid
classDiagram
  class ClassGroup
  class Student
  class Company
  class FinanceDept
  ClassGroup o-- Student : aggregation
  Company *-- FinanceDept : composition

例如班级毕业后,学生仍然存在,所以班级和学生更像聚合。公司破产后,作为该公司的财务部也就失去独立意义,所以公司与财务部更像组合。

用例图中的三种关系

用例图关系主要考包含、扩展、泛化。它们都可能用箭头,但含义完全不同。

关系英文标注含义是否必选箭头指向典型判断
包含<<include>>抽取多个用例共同的公共行为必选被包含的公共用例每次执行基本用例都必须执行公共用例
扩展<<extend>>在满足条件时追加额外行为可选被扩展的基本用例“若……则……”“余额不足才……”
泛化Generalization抽象出父用例,执行时选择某个子用例必选选择其一父用例子用例是父用例的一种

包含关系:公共步骤被抽出来

包含关系用于提取公共行为。多个基本用例都要做同一件事,就把它抽成公共用例。

mermaid
flowchart LR
  A["学习课程"] -. "<<include>>" .-> C["检查权限"]
  B["课程测试"] -. "<<include>>" .-> C

箭头指向被包含的公共用例。这里“检查权限”不是可做可不做,而是学习课程、课程测试之前都必须执行。

扩展关系:满足条件才追加

扩展关系表示条件分支。基本用例本身可以正常完成,只有满足特定条件时才执行扩展用例。

mermaid
flowchart LR
  E["充值学习币"] -. "<<extend>>\n余额不足" .-> F["课程测试"]

箭头指向被扩展的基本用例。余额充足时,课程测试可以直接进行;余额不足时,才扩展出“充值学习币”。

泛化关系:父用例抽象,子用例真正执行

泛化关系类似类的继承:父用例抽取共性,子用例是具体实现。

mermaid
flowchart BT
  P["电话注册"] --> R["课程注册"]
  W["网上注册"] --> R

实际 UML 符号中,子用例指向父用例,箭头是空心三角。语义上是“电话注册是一种课程注册”“网上注册是一种课程注册”。父用例较抽象,具体执行时要选择某一种子用例。

include、extend、泛化的辨析

问题包含扩展泛化
是否一定发生一定发生条件满足才发生必须选择某个具体子用例
抽取的是什么多个用例共有的公共步骤某个条件下的附加步骤多个具体用例的共同抽象
基本用例能否脱离它正常完成不能,公共步骤必须执行能,扩展用例可不执行父用例抽象,具体要落到子用例
需求描述线索“都需要”“必须先”“若……则……”“当……时”“是一种”“可分为”

把三者放进一句话中理解:

  • 包含:做 A 必然也要做 B,所以把 B 抽出来复用。
  • 扩展:平时做 A 即可,特殊条件下才追加 B。
  • 泛化:A 只是抽象说法,真正执行的是 A1 或 A2。

例题

单选
部分对象生命周期强依赖整体对象,通常表示为:
单选
多个基本用例都必须执行同一个“检查权限”步骤,适合抽取为:
单选
“余额不足时才需要充值学习币”这种条件性附加行为,适合表示为:

自查要点

  1. 泛化和实现的箭头分别指向谁?
  2. 聚合与组合为什么不能只靠“整体-部分”四个字判断?
  3. include 和 extend 的箭头都很容易看反,应该怎样记忆?
  4. 两个类之间能否有多个关联?多个关联通常靠什么区分?