UML 类图与时序图:面向对象设计表达

FreeGuideOnline 最新 2026-07-01

UML 类图与时序图:面向对象设计表达

什么是UML

统一建模语言(UML)是一种标准化的可视化建模语言,用于在软件开发过程中对系统进行规约、可视化、构造和文档化。它帮助团队在编码之前理解、设计复杂系统的结构和行为。本教程聚焦于两种最常用的UML图:类图用于表达静态结构,时序图用于展示动态交互。

第一部分:类图——系统的静态蓝图

类图是面向对象系统的核心建模工具,它描述了系统中类的集合、类的内部结构以及类之间的各种关系。它不关心时间或流程,而是回答“有哪些部分”和“它们之间如何关联”的问题。

类的表示法

在UML中,一个类用一个被分为三层的矩形表示:

  • 顶层:类名(正体,抽象类用斜体)。
  • 中间层:属性列表。
  • 底层:方法(操作)列表。
+----------------------------+
|        ClassName           |
+----------------------------+
| - attribute1 : DataType    |
| - attribute2 : DataType    |
+----------------------------+
| + method1() : ReturnType   |
| + method2(param : Type)    |
+----------------------------+

可见性修饰符

  • + 公开 (public)
  • - 私有 (private)
  • # 受保护 (protected)
  • ~ 包内可见 (package)

属性完整语法
可见性 名称 : 类型 [多重性] = 默认值 {约束}
示例:- balance : double = 0.0 {non-negative}

方法完整语法
可见性 名称(参数列表) : 返回类型
示例:+ withdraw(amount : double) : bool

核心关系类型:从弱到强

理解关系是读懂类图的关键。下表涵盖了所有基础关系:

关系类型 符号风格 箭头含义 代码体现 说明
依赖 带箭头的虚线 ----> 使用者指向被使用者 局部变量、方法参数 一种暂时的、最弱的 “使用” 关系。类A的变化可能影响类B。
关联 实线 —— 或带箭头实线 ——> 导航方向 成员变量 一种稳定的结构关系。类A持有对类B的引用。可标注多重性。
聚合 空心菱形加实线 ◇—— 整体指向部分 成员变量(可共享) 弱 “拥有” 关系,部分可以脱离整体独立存在。如:球队与球员。
组合 实心菱形加实线 ◆—— 整体指向部分 成员变量(不可共享) 强 “拥有” 关系,部分的生命周期由整体控制。如:订单与订单行目。
实现 带三角的虚线 ----▷ 实现者指向接口 implements 关键字 类实现接口中的抽象方法。
泛化 带三角的实线 ——▷ 子类指向父类 extends 关键字 继承,代表 “是一种” 的关系。抽象类和抽象方法用斜体。

多重性标注:在关联关系的两端标注数字或范围,表示“多少个”。

  • 1 严格1个
  • 0..1 0或1个
  • *0..* 0到多个
  • 1..* 至少1个
  • 示例:Customer 1 —— * Order 表示一个客户有多个订单,一个订单只属于一个客户。

类图实例解读

下面是一个简化的电商订单域类图:

+------------------+                +-------------------+
|    Customer      |                |      Order        |
+------------------+                +-------------------+
| - id : String    |  1          *  | - orderId : String |
| - name : String  |◇──────────────▶| - date : Date      |
+------------------+                +-------------------+
                                          |
                                          | 1
                                          |
                                          | ◆ 组合(强拥有)
                                          |
                                          1..*
                                   +-------------------+
                                   |    OrderItem      |
                                   +-------------------+
                                   | - quantity : int  |
                                   +-------------------+
                                   | + getSubTotal()   |
                                   +-------------------+
  • Customer与Order是一对多关联,且为聚合(空心菱形),因为订单保留客户信息,但客户删除时订单可能仍然存在。
  • Order与OrderItem是组合,项的生命周期完全依赖订单,订单取消则行目消失。
  • 多重性表示每个订单至少包含一个订单行目。

第二部分:时序图——捕捉对象间的对话

时序图诠释了特定场景下对象之间消息传递的时间顺序。它垂直向下表示时间流逝,水平方向排列参与者,重点在于“谁在什么时间对谁说了什么”。

基本构件

  • 生命线:从每个对象图标向下延伸的虚线,表示对象存在的时间段。
  • 激活条:生命线上的细长矩形,表示对象正在执行操作、处于活动状态的时间。
  • 消息:带箭头的水平线,从一个生命线指向另一个。类型包含:
    • 同步消息:实线实心箭头 —▶,调用者等待返回。
    • 返回消息:虚线开箭头 --▷,一般表示同步调用的返回。
    • 异步消息:实线开箭头 —▷,发送后不等待,继续执行。
    • 自调用消息:箭头指向自己,表示对象内部方法调用。
    • 创建消息:虚线开箭头指向新创建对象的生命线头部,配上 <<create>> 构造型。
  • 片段与组合:用矩形框住一组交互,标签如 alt(条件分支)、loop(循环)、opt(可选)、par(并行)等,能够表达复杂控制流。

建模顺序:从左到右,从上到下

  1. 确定场景上下文(例如“用户成功支付订单”)。
  2. 绘制参与对象:从左到右放置,通常将发起者放在最左,重要处理器放中间,外部系统放右侧。
  3. 用消息线逐条绘制交互,并在激活条上标明执行期。
  4. 利用组合片段表达条件逻辑和循环。

时序图实例:电商订单支付流程

以下示例展示一个包含条件判断的支付场景。

用户          订单服务        支付网关        库存服务
│               │               │               │
│  placeOrder() │               │               │
├──────────────▶│               │               │
│               │  激活         │               │
│               ├─────────────┐ │               │
│               │ 校验订单    │ │               │
│               │◄────────────┘ │               │
│               │               │               │
│               │ processPayment(amount)         │
│               ├──────────────▶│               │
│               │               │ 激活          │
│               │               ├─────────────┐ │
│               │               │ 授权交易    │ │
│               │               │◄────────────┘ │
│               │               │               │
│               │   alt [授权成功]               │
│               │               │               │
│               │  paymentSuccess()               │
│               │◄──────────────│               │
│               │               │               │
│               │  updateInventory(itemId, qty)  │
│               ├──────────────────────────────▶│
│               │               │               │ 激活
│               │               │               ├────┐
│               │               │               │扣减│
│               │               │               │◄───┘
│               │  invOK()      │               │
│               │◄──────────────────────────────│
│               │               │               │
│               │   [授权失败]                   │
│               │  paymentFailed(reason)         │
│               │◄──────────────│               │
│               │               │               │
│               │   end         │               │
│               │               │               │
│  orderResult  │               │               │
│◄──────────────│               │               │
│               │               │               │

解读

  • 用户调用订单服务的 placeOrder(),触发内部校验。
  • 订单服务向支付网关发送同步消息 processPayment,并等待返回。
  • 片段 alt 根据支付结果分为两个路径:成功时调用库存服务扣减,失败时仅返回失败原因。
  • 所有返回用虚线箭头表示,最后订单服务将结果返回给用户。

实践准则与常见误区

类图

  • 牢记目的:它是结构蓝图,不是实现图。不要在类图中画流程。
  • 关系不要混用:除非有“部分-整体”特征且部分不能独立存在,否则不要轻易使用组合。大多数情况用关联或聚合。
  • 属性 vs 关联:如果某个概念自身有丰富属性和行为,应作为类并用关联连接;如果只是基本类型(String、int),作为属性即可。

时序图

  • 聚焦关键路径:一张时序图只描绘一个清晰场景,不要试图把所有异常分支揉进一张图。
  • 避免过度详细:只表达核心对象间的协作,底层工具类或 trivial 的 getter/setter 通常不画。
  • 合理使用片段altloop 虽可表达逻辑,但不要让时序图变成程序流程图。坚持“主要成功路径”优先原则。

工具推荐

  • 免费在线工具:PlantUML (文本驱动)、draw.io、Lucidchart
  • 集成开发环境插件:IntelliJ IDEA Ultimate 自带 UML 生成,VS Code 有 PlantUML 插件

结语

掌握类图和时序图,你就能清晰地表达面向对象设计的静态骨架和动态协作。从简单的小模块开始练习,逐渐过渡到完整的系统模块,你会发现UML成为沟通设计、降低复杂度的有力助手。