Thinking in UML 大象:用例驱动的建模思想与实践

引言

在软件开发的历史中,统一建模语言(Unified Modeling Language,UML)是每个软件工程师必备的技能。最近在看一非常不错的UML相关书籍:《大象:Thinking in UML》,这本书的核心价值在于:它不仅仅教我们如何画 UML 图,更重要的是传达了一种用例驱动的建模思想。这种思想帮助我们建立从现实世界到软件设计的映射路径,让复杂系统的分析和设计变得有章可循。

“建模就像写文章,UML 的元素、规则就像文章中的文字和语法。”

本文将围绕这本书的核心内容,系统梳理 UML 建模的基础知识、核心元素、实践方法以及高级思考,帮助读者建立完整的 UML 建模知识体系。


第一部分:UML 带来了什么

面向对象的困难与 UML 的应对

面向对象方法学从诞生之初就面临着认知上的困难。我们习惯于用过程化的思维思考问题,而面向对象要求我们将世界看作一个个相互独立的对象。

面向对象的本质认识

“面向对象方法将世界看作一个个相互独立的对象,相互之间并无因果关系,它们平时是’鸡犬之声相闻,老死不相往来’的。只有在某个外部力量的驱动下,对象之间才会依据某种规律相互传递信息。”

这种思维方式的转变带来了三个根本问题:

问题 描述 UML 的解决方案
Why 对象是怎么被抽象出来的?为什么要这么抽象而不是那么抽象? 用例驱动方法,从参与者目标出发
How 什么样的组合是好的,什么样的组合是差的? 设计原则和模式指导
What 如果只给我一个对象组合,我怎么才能理解它表达了怎样的含义? 可视化视图和模型组织

抽象是面向对象的精髓所在,同时也是面向对象的困难所在。 UML 通过提供一套标准的建模元素和规则,帮助我们克服这些困难。

UML 的本质:统一语言与可视化

UML 的本质是什么?书中给出了清晰的定义:

“UML 是一种建模用的语言,而所有的语言都是由基本词汇和语法两个部分构成的。”

UML 带来的三个核心价值

价值 说明 实践意义
统一语言 构设在团队、角色之间的沟通桥梁 需求分析师、架构师、开发者、测试人员使用相同的术语
可视化 把”隐晦”的变成”可视”的 通过图形直观表达复杂的业务关系和系统结构
建模方法 从现实世界到软件设计的映射路径 提供完整的分析设计流程指导

“UML 通过它的元模型和表示法,把那些通过文字或其他表达方法很难表达清楚的、隐晦的潜台词用简单直观的图形表达和暴露出来,准确而直观地描述复杂的含义。”

在 2012 年的软件开发实践中,UML 的价值主要体现在:

  1. 需求分析阶段:用用例图捕获用户需求
  2. 系统设计阶段:用类图、时序图设计系统架构
  3. 团队沟通阶段:用标准图形替代文字描述,减少歧义
  4. 文档归档阶段:形成可追溯的设计文档

从现实世界到设计模型的映射

UML 提供了一条清晰的从现实世界到软件设计的映射路径:

graph LR
    A[现实世界] -->|业务建模| B[业务模型]
    B -->|概念建模| C[分析模型]
    C -->|详细设计| D[设计模型]
    D -->|编码实现| E[可执行系统]

    style A fill:#e1f5ff,stroke:#0288d1,color:#01579b
    style B fill:#fff3e0,stroke:#f57c00,color:#e65100
    style C fill:#f3e5f5,stroke:#7b1fa2,color:#4a148c
    style D fill:#e8f5e9,stroke:#388e3c,color:#1b5e20
    style E fill:#fff9c4,stroke:#fbc02d,color:#f57f17

各阶段的输入输出

阶段 输入 核心工作 输出
业务建模 现实世界业务 参与者访谈、用例获取、业务场景 业务用例模型、领域模型
概念建模 业务模型 分析类提取、用例实现 分析模型、软件架构
设计建模 分析模型 类设计、接口设计、包设计 设计模型、组件模型
编码实现 设计模型 代码生成、单元测试 可执行系统

“现实世界无论多复杂,无论是哪个行业,无论做什么业务,其本质无非是由人、事、物和规则组成的。”

这条映射路径的关键在于保持可追溯性:每一阶段的设计元素都应该能追溯到上一阶段,最终追溯到现实世界的业务需求。


第二部分:UML 核心元素详解

参与者:建模的核心地位

参与者(Actor)是 UML 建模的起点,也是整个系统的驱动力来源。

定义:参与者是模型信息来源的提供者,也是第一驱动者。

参与者的核心特征

特征 说明 示例
位于边界之外 参与者总是在系统边界之外 ATM 系统的”存款人”
可以非人 参与者不一定是人 定时器、传感器、外部系统
涉众的代表 代表与系统有利益关系的一方 “局长”代表”投资机构”
第一驱动者 主动发起与系统的交互 用户点击登录按钮

“参与者对系统的要求,对系统的表述完全决定了系统的功能性。”

参与者 vs 容易混淆的概念

概念 定义 位置 主动/被动
业务主角 业务系统中的参与者 边界之外 主动发起动作
业务工人 边界内被动参与者 边界之内 被动响应
涉众 与系统有利益关系的一切人和事 - -
用户 参与者的代理或实例 - -
角色 参与者的职责 - -

发现参与者的方法

  1. 回答两个问题:
    • 谁对系统有着明确的目标和要求并且主动发出动作?
    • 系统是为谁服务的?
  2. 从业务流程中寻找:
    • 谁启动了业务流程?
    • 谁从系统中获得价值?
    • 系统需要与哪些外部系统交互?

用例:从功能到目标的转变

用例(Use Case)是 UML 建模的核心,也是用例驱动方法的基石。

定义:与参与者交互的,并且给参与者提供可观测的有意义的结果的一系列活动的集合。

用例的构成

一个用例 = <参与者,前置条件,{场景},后置条件>

用例的五大特征

特征 说明 正例 反例
相对独立 不需要与其他用例交互而独自完成参与者的目的 取钱 填写取款单
可观测结果 结果对参与者来说是可观测的和有意义的 查询余额 后台数据备份
参与者发起 必须由一个参与者发起 取款 ATM 自动吐钞
动宾结构 以动宾短语形式出现 “修改密码” “密码”
有意义的结果 对参与者有明确的意义 转账成功 输入密码

用例 vs 功能:这是书中重点强调的误区

方面 用例 功能
视角 参与者角度 事物角度
描述 人们能够用它做什么 它能做什么
性质 使用者观点 功能性观点
示例 “购买商品” “商品管理功能”

“功能是用事物角度出发的,而用例是从参与者角度出发的。功能是脱离使用者的愿望存在的。功能是孤立的,而用例是一个系统性的工作。”

这个区分看似简单,但在实际建模中经常被混淆。正确理解用例,是用例驱动方法的第一步。

边界:决定视界与抽象层次

边界(Boundary)是面向对象方法中一个非常重要但容易被忽视的概念。

定义:边界本质上是面向对象方法的一个很重要的概念,与封装的概念师出同源。

边界的两个核心作用

作用 说明 实践意义
决定视界 边界决定了你看到的东西 设定系统范围,明确什么在系统内,什么在系统外
决定抽象层次 通过设定边界来控制分析粒度 边界越大,粒度越粗;边界越小,粒度越细

“边界和封装概念师出同源,边界决定着抽象的层次,也就是它决定着分析粒度的大小。”

“能否准确把握边界,能否灵活变换边界,能否控制边界的粒度是做好需求分析和系统设计的关键。”

边界的相对性

边界不是固定不变的,而是可以根据分析需要灵活调整的:

边界大小 分析粒度 适用场景 示例
大边界 粗粒度 业务建模、概念建模 “图书馆借阅系统”
中边界 中粒度 系统分析 “借书模块”
小边界 细粒度 详细设计 “借书审批流程”

边界调整的策略

graph TD
    A[发现建模困难] --> B{检查边界}
    B -->|粒度不一致| C[调整边界大小]
    B -->|信息过载| D[缩小边界范围]
    B -->|信息不足| E[扩大边界范围]

    C --> F[重新获取用例]
    D --> F
    E --> F

    style A fill:#ffebee,stroke:#d32f2f,color:#b71c1c
    style B fill:#fff3e0,stroke:#f57c00,color:#e65100
    style C fill:#e1f5ff,stroke:#0288d1,color:#01579b
    style D fill:#f3e5f5,stroke:#7b1fa2,color:#4a148c
    style E fill:#e8f5e9,stroke:#388e3c,color:#1b5e20
    style F fill:#e8f5e9,stroke:#388e3c,color:#1b5e20

业务实体、分析类、设计类

UML 建模中,不同阶段使用不同抽象层次的类概念。

业务实体(Business Entity)

定义:代表业务角色执行业务用例时所处理或使用的”事物”。

获取业务实体的方法:

  1. 建立业务用例场景
  2. 分析动词后面的名词
  3. 筛选对业务目标有贡献的对象
  4. 分析关系,决定哪些单独建模,哪些作为属性

分析类(Analysis Class)

分析类是跨越需求到设计实现的桥梁,分为三种:

类型 图符 职责 架构层次 示例
边界类 ◇︎ 系统外部环境与其内部运作之间的交互 展现层 网页、窗口、API
控制类 对一个或几个用例所特有的控制行为进行建模 业务逻辑层 购买、验证、发送
实体类 对必须存储的信息和相关行为建模 数据持久层 订单、商品、客户

“分析类就是跨越需求到设计实现的桥梁。”

分析类的”三高”特征:

  • 高于设计实现 - 不理会复杂的设计要求
  • 高于编程语言 - 不受特定语言约束
  • 高于技术细节 - 专注于逻辑结构

三种分析类的关系

graph TD
    A[边界类<br/>Boundary] -->|调用| B[控制类<br/>Control]
    B -->|操作| C[实体类<br/>Entity]

    A1[用户界面] -->|A| B1[业务逻辑]
    B1 -->|B| C1[数据对象]

    style A fill:#e1f5ff,stroke:#0288d1,color:#01579b
    style B fill:#fff3e0,stroke:#f57c00,color:#e65100
    style C fill:#f3e5f5,stroke:#7b1fa2,color:#4a148c
    style A1 fill:#e8f5e9,stroke:#388e3c,color:#1b5e20
    style B1 fill:#fff9c4,stroke:#fbc02d,color:#f57f17
    style C1 fill:#fce4ec,stroke:#d81b60,color:#ad1457

设计类(Design Class)

设计类是分析类的具体化,需要考虑:

  • 具体的编程语言特性
  • 框架和平台的要求
  • 性能、安全等技术约束
  • 设计模式的应用

九种关系:关联、依赖、扩展、包含、实现、精化、泛化、聚合、组合

UML 定义了丰富的关系类型,理解和正确使用这些关系是建模的关键。

九种关系分类

graph TD
    A[UML关系] --> B[关系型]
    A --> C[依赖型]
    A --> D[层次型]

    B --> E[关联]
    B --> F[聚合]
    B --> G[组合]

    C --> H[依赖]
    C --> I[扩展]
    C --> J[包含]

    D --> K[实现]
    D --> L[精化]
    D --> M[泛化]

    style A fill:#e1f5ff,stroke:#0288d1,color:#01579b
    style B fill:#fff3e0,stroke:#f57c00,color:#e65100
    style C fill:#f3e5f5,stroke:#7b1fa2,color:#4a148c
    style D fill:#e8f5e9,stroke:#388e3c,color:#1b5e20

关系详解

关系类型 符号 语义 代码含义 示例
关联 实线 类之间的引用关系 class A { B b; } 客户关联订单
依赖 虚线箭头 临时使用关系 函数参数使用 订单处理依赖支付服务
扩展 虚线+«extend» 可选的扩展行为 条件分支 支付扩展退款
包含 虚线+«include» 必须包含的行为 方法调用 支付包含身份验证
实现 虚线+空心三角 接口实现 implements 类实现接口
精化 虚线+空心三角 抽象层次之间的细化 概念→具体 分析类精化为设计类
泛化 实线+空心三角 is-a 关系 extends 子类继承父类
聚合 空心菱形+实线 has-a 关系,弱拥有 成员变量,可独立存在 部门包含员工
组合 实心菱形+实线 contains-a 关系,强拥有 成员变量,生命周期绑定 订单包含订单项

聚合 vs 组合:这是最容易混淆的一对关系

方面 聚合 (Aggregation) 组合 (Composition)
关系强度 弱拥有 强拥有
生命周期 独立 绑定
共享性 可被多个父对象共享 只能属于一个父对象
销毁 父对象销毁,子对象仍可存在 父对象销毁,子对象随之销毁
代码示例 class Car { Engine* engine; } class Car { Wheel wheel; }
现实类比 班级包含学生 人包含心脏

选择关系的决策树

两个类之间存在关系?
    ↓
是"整体-部分"关系吗?
    YES → 部分能独立存在吗?
        YES → 聚合
        NO  → 组合
    NO  → 是"is-a"关系吗?
        YES → 泛化
        NO  → 是临时使用吗?
            YES → 依赖
            NO  → 关联


第三部分:UML 核心视图

静态视图:用例图、类图、包图

UML 视图分为静态视图和动态视图两大类。静态视图描述系统的结构特征,动态视图描述系统的行为特征。

UML 视图分类

graph TD
    A[UML视图] --> B[静态视图]
    A --> C[动态视图]

    B --> D[用例图]
    B --> E[类图]
    B --> F[包图]

    C --> G[活动图]
    C --> H[状态图]
    C --> I[时序图]
    C --> J[协作图]

    style A fill:#e1f5ff,stroke:#0288d1,color:#01579b
    style B fill:#fff3e0,stroke:#f57c00,color:#e65100
    style C fill:#f3e5f5,stroke:#7b1fa2,color:#4a148c

用例图(Use Case Diagram)

用例图是 UML 中最基础的视图,用于描述系统的功能需求。

用例图的组成元素

元素 符号 说明
参与者 小人图标 系统外部的实体
用例 椭圆 系统提供的功能
系统边界 矩形框 界定系统范围
关联 实线 参与者与用例的关系
包含 虚线+«include» 基础用例必须包含的行为
扩展 虚线+«extend» 可选的扩展行为

ATM 系统用例图示例

graph TD
    A[存款人] -->|取款| UC1(取款)
    A -->|查询余额| UC2(查询余额)
    A -->|修改密码| UC3(修改密码)
    B[银行系统] -->|管理账户| UC4(账户管理)
    C[管理员] -->|系统维护| UC5(系统管理)

    style A fill:#e1f5ff,stroke:#0288d1,color:#01579b
    style B fill:#fff3e0,stroke:#f57c00,color:#e65100
    style C fill:#f3e5f5,stroke:#7b1fa2,color:#4a148c

用例图的实践价值

  • 需求获取和验证的工具
  • 项目估算的依据
  • 测试用例设计的基础
  • 用户沟通的媒介

类图(Class Diagram)

类图是 UML 中最重要的视图,描述系统的静态结构。

类图的组成元素

一个类由三部分组成:

  • 名称:类的名称
  • 属性:类的特征
  • 方法:类的行为

用户类图示例

classDiagram
    class User {
        +String userId
        +String username
        +String email
        +String password
        +register() void
        +login() boolean
        +logout() void
    }

    class Customer {
        +String address
        +String phone
        +List~Order~ orders
        +placeOrder() Order
        +cancelOrder() void
    }

    class Administrator {
        +String department
        +List~String~ permissions
        +manageUsers() void
        +configureSystem() void
    }

    User <|-- Customer : 继承
    User <|-- Administrator : 继承

类图的核心价值

  • 系统静态结构的完整描述
  • 数据库设计的基础
  • 代码生成的依据
  • 架构评审的工具

包图(Package Diagram)

包图用于组织模型元素,体现了”高内聚、低耦合”的设计原则。

系统分层包图示例

graph TD
    subgraph Presentation[表示层]
        UI[用户界面组件]
        API[API 接口]
    end

    subgraph Business[业务层]
        Service[业务服务]
        Domain[领域模型]
        Rules[业务规则]
    end

    subgraph Persistence[持久层]
        DAO[数据访问对象]
        ORM[ORM 映射]
    end

    Presentation -->|依赖| Business
    Business -->|依赖| Persistence

    style Presentation fill:#e1f5ff,stroke:#0288d1,color:#01579b
    style Business fill:#fff3e0,stroke:#f57c00,color:#e65100
    style Persistence fill:#f3e5f5,stroke:#7b1fa2,color:#4a148c

包图的核心价值

  • 体现系统的分层架构
  • 控制依赖关系
  • 指导代码组织结构

动态视图:活动图、状态图、时序图

动态视图描述系统的行为特征,展示系统在运行时的状态变化和交互过程。

活动图(Activity Diagram)

活动图用于描述业务流程和工作流。

网上购物流程活动图示例

flowchart TD
    START([开始]) --> Browse[浏览商品]
    Browse --> |选择商品| AddCart[加入购物车]
    AddCart --> ViewCart[查看购物车]

    ViewCart --> |继续购物| Browse
    ViewCart --> |去结算| CheckLogin{已登录?}

    CheckLogin --> |否| Login[登录/注册]
    Login --> Checkout[填写订单信息]

    CheckLogin --> |是| Checkout
    Checkout --> Confirm[确认订单]
    Confirm --> Pay[选择支付方式]
    Pay --> ProcessPay[处理支付]
    ProcessPay --> |成功| Success[支付成功]
    ProcessPay --> |失败| Fail[支付失败]

    Fail --> |重新支付| Pay
    Fail --> |取消订单| Cancel([取消])

    Success --> Ship[等待发货]
    Ship --> Receive([确认收货])
    Receive --> END([结束])

活动图的核心价值

  • 业务流程的可视化
  • 工作流设计的依据
  • 业务规则梳理的工具

状态图(State Diagram)

状态图描述对象的生命周期和状态转换。

订单状态图示例

stateDiagram-v2
    [*] --> 待支付: 创建订单
    待支付 --> 已取消: 超时未支付
    待支付 --> 已支付: 支付成功
    待支付 --> 已关闭: 系统关闭

    已支付 --> 待发货: 支付确认
    待发货 --> 已发货: 商家发货
    待发货 --> 已退款: 申请退款

    已发货 --> 待收货: 物流更新
    待收货 --> 已完成: 确认收货
    待收货 --> 已退款: 申请退款

    已完成 --> [*]
    已取消 --> [*]
    已关闭 --> [*]
    已退款 --> [*]

状态图的核心价值

  • 明确对象的生命周期
  • 定义状态转换规则
  • 指导状态机实现

时序图(Sequence Diagram)

时序图描述对象之间交互的时间顺序。

用户登录时序图示例

sequenceDiagram
    actor U as 用户
    participant UI as 登录界面
    participant C as 控制器
    participant S as 用户服务
    participant D as 数据库
    participant A as 认证服务

    U->>UI: 输入用户名密码
    UI->>C: 提交登录请求
    C->>S: 验证用户信息
    S->>D: 查询用户数据
    D-->>S: 返回用户信息
    S->>A: 验证密码

    alt 密码正确
        S->>A: 生成令牌
        A-->>S: 返回令牌
        S-->>C: 登录成功+令牌
        C-->>UI: 跳转首页
    else 密码错误
        S-->>C: 登录失败
        C-->>UI: 显示错误信息
    end

时序图的核心价值

  • 清晰展示交互流程
  • 验证用例实现
  • 指导接口设计

第四部分:实践流程指南

准备工作:涉众分析与边界定义

UML 建模的第一步不是画图,而是准备工作。准备工作的质量决定了后续建模的效果。

涉众分析

涉众(Stakeholder)是与系统有利益关系的所有人和事。识别涉众是建模的起点。

涉众分类

类型 说明 示例
参与者 系统外部主动发起动作的实体 用户、外部系统
业务工人 边界内被动参与者 银行柜台职员
受益者 从系统中获得价值的人 企业老板、管理层
监管者 对系统有约束力的人 审计部门、监管机构

定义系统边界

通过两个问题确定边界:

  1. 谁对系统有着明确的目标和要求并且主动发出动作?
  2. 系统是为谁服务的?

边界定义的实践建议

情况 建议
初次建模 从大边界开始,把握整体业务
需求复杂 划分多个子边界,逐个分析
需求变化 灵活调整边界,不拘泥于初始设定

获取需求:用例获取的实践方法

获取用例是建模过程中最关键的环节,也是最容易出错的环节。

避免的做法

❌ 错误做法 ✅ 正确做法
让客户描述整个业务流程 引导客户描述目标和期望
涉及表单填写等业务细节 关注业务目标,忽略实现细节
让客户理解将来的计算机系统 用客户的业务语言交流
从流程图开始建模 从参与者访谈开始

正确的引导问题

  1. 您对系统有什么期望?
  2. 您打算在这个系统里做些什么事情?
  3. 您做这件事的目的是什么?
  4. 您做完这件事希望有一个什么样的结果?

用例有效性检查表

检查项 说明 正例 反例
独立完整性 能独立完成参与者的目的 取钱 填写取款单
可观测性 结果对参与者可观测 登录系统 后台备份
主动发起 由参与者发起 取款 ATM 自动吐钞
动宾结构 以动宾短语命名 “修改密码” “密码”
有意义结果 对参与者有明确意义 转账成功 输入密码

用例获取示例分析(ATM 取款场景):

客户表达 分析结果 是否用例
“我希望这台 ATM 能支持跨行业务” 功能描述,不是用户目标
“插入卡片” 操作步骤,不是完整目标
“输入密码” 操作步骤,不是完整目标
“选择服务” 操作步骤,不是完整目标
“取钱” 完整的用户目标
“存钱” 完整的用户目标
“挂失卡片” 完整的用户目标
“交纳费用” 完整的用户目标
“警示骗子” 系统属性,不是功能目标
“三次错误吞没卡片” 业务规则,不是用例

系统分析:分析类与用例实现

获取用例后,下一步是进行系统分析,建立分析模型。

用例实现的步骤

flowchart TD
    START[开始用例实现] --> Identify[识别边界类]
    Identify --> Extract[提取控制类]
    Extract --> Find[寻找实体类]
    Find --> Model[建立关系模型]
    Model --> Sequence[绘制时序图]
    Sequence --> Verify[验证场景完整性]
    Verify --> END[完成用例实现]

    style START fill:#e1f5ff,stroke:#0288d1,color:#01579b
    style END fill:#e8f5e9,stroke:#388e3c,color:#1b5e20

分析类的获取来源

分析类 来源 示例
边界类 参与者与用例的交互点 网页、窗口、API、协议
控制类 用例场景中的动词行为 购买、计算、验证、发送
实体类 业务实体 订单、商品、客户

用例实现的实践建议

  1. 从场景开始:先用文字描述用例的场景,再转换为分析类
  2. 关注职责:每个分析类应该有清晰的职责
  3. 保持简单:分析类不应该涉及设计细节
  4. 可追溯性:每个分析类都应该能追溯到需求

系统设计:从分析模型到设计模型

分析模型完成后,下一步是转换为设计模型。

分析模型到设计模型的转换

graph TD
    A[业务用例] -->|映射为| B[概念用例]
    B -->|实现为| C[系统用例]

    D[业务实体] -->|转化为| E[实体类]
    E -->|设计为| F[数据表]

    G[业务场景] -->|抽象为| H[控制类]
    H -->|实现为| I[业务逻辑]

    J[参与者] -->|转化为| K[用户]
    K -->|配置为| L[权限角色]

    style A fill:#e1f5ff,stroke:#0288d1,color:#01579b
    style B fill:#fff3e0,stroke:#f57c00,color:#e65100
    style C fill:#f3e5f5,stroke:#7b1fa2,color:#4a148c

设计模型需要考虑的问题

方面 分析模型 设计模型
抽象层次 高抽象,关注逻辑结构 低抽象,关注实现细节
技术约束 不考虑技术约束 考虑框架、平台、性能
设计模式 不涉及 应用适当的设计模式
代码映射 不能直接映射 可以直接映射到代码

架构设计的基本构成

graph TB
    subgraph 架构层次
        P[表示层<br/>展现层]
        B[业务层<br/>业务逻辑层]
        D[数据层<br/>持久层]
        I[集成层<br/>外部接口]
    end

    P -->|调用| B
    B -->|访问| D
    I -->|通信| B

    subgraph 横切关注点
        S1[安全]
        S2[日志]
        S3[缓存]
        S4[事务]
    end

    S1 & S2 & S3 & S4 -.影响.-> P
    S1 & S2 & S3 & S4 -.影响.-> B
    S1 & S2 & S3 & S4 -.影响.-> D

    style P fill:#e1f5ff,stroke:#0288d1,color:#01579b
    style B fill:#fff3e0,stroke:#f57c00,color:#e65100
    style D fill:#f3e5f5,stroke:#7b1fa2,color:#4a148c
    style I fill:#e8f5e9,stroke:#388e3c,color:#1b5e20


第五部分:高级思考与最佳实践

用例的本质再理解

理解用例的本质,是用例驱动方法成功的关键。

用例是系统思维

“用例体现了一种系统思维,即把软件看作一个为参与者提供服务的系统,而不是一堆功能的集合。”

系统思维 vs 功能思维

维度 系统思维(用例) 功能思维
关注点 参与者的目标和价值 功能的划分和实现
视角 使用者视角 开发者视角
组织方式 以参与者为中心组织 以功能模块为中心组织
验证标准 是否满足参与者目标 是否完成功能开发

用例是面向服务的

“用例本质上是面向服务的,每个用例都是系统为参与者提供的一项服务。”

服务导向的特征:

  1. 服务是可访问的(通过边界)
  2. 服务是有价值的(对参与者有意义)
  3. 服务是独立的(可完整交付)
  4. 服务是可组合的(可构成更大服务)

抽象层次的实战应用

抽象层次是 UML 建模中最重要的概念之一,也是最难掌握的。

抽象层次的原则

“抽象层次越高,信息量越少(多数信息被封装或屏蔽),相对的越容易被理解。但过高又会产生信息量不足的问题,在合适的时候采用适当的抽象层次十分重要。”

UML 中的抽象层次体现

业务建模层(高抽象)
├── 业务用例模型
├── 领域模型
└── 业务架构

概念建模层(中抽象)
├── 概念用例模型
├── 分析模型
└── 软件架构

设计建模层(低抽象)
├── 系统用例模型
├── 设计模型
└── 组件模型

实现建模层(最低抽象)
├── 类设计
├── 数据库设计
└── 部署模型

决定抽象层次的因素

因素 高抽象 低抽象
沟通对象 业务人员、项目经理 开发人员、测试人员
文档目的 需求理解、范围界定 设计指导、代码实现
项目阶段 早期需求分析 后期详细设计
系统复杂度 复杂系统(宏观把握) 简单系统(直接设计)

层次不交叉原则

同一抽象层次的内容应当放在一起,不要在一个层次中混杂其他层次的内容。

系统边界的战略运用

边界是面向对象的保障,也是建模的核心技巧。

边界是面向对象的保障

“边界是面向对象的保障,没有边界就没有对象。”

边界的核心作用

作用 说明
封装隔离 将相关内容封装在一起
职责分离 不同边界承担不同职责
依赖控制 控制跨边界的依赖关系
复杂度管理 通过边界控制信息量

边界的艺术

“好的设计如同一筐带壳的鸡蛋,清清爽爽;差的设计如同一堆打碎了壳的鸡蛋,粘粘糊糊。’壳’是好坏的关键。”

边界意识的表现

  1. 心中有边界:时刻意识到边界存在
  2. 灵活变换边界:根据需要调整边界
  3. 控制边界粒度:选择合适的抽象层次
  4. 尊重边界约束:不随意跨越边界

接口是系统的灵魂

接口设计是系统设计中最重要的一环。

从接口认知事物

描述一件事物有三种观点:

  1. 结构性观点:这个事物是什么?
  2. 功能性观点:这个事物能做什么?
  3. 使用者观点:人们能够用这个事物做什么?

UML 选择使用者观点:从参与者角度出发,关注交互和价值。

“接口是系统的灵魂,接口设计的好坏直接决定了系统的可扩展性、可维护性和可测试性。”

接口的核心价值

价值 说明
解耦 通过接口隔离具体实现
扩展 通过接口支持多种实现
复用 通过接口实现组件复用
测试 通过接口进行 Mock 测试

接口设计的原则

  • 接口应当是稳定的
  • 接口应当是语义化的
  • 接口应当是高内聚的
  • 接口应当是向前兼容的

总结

通过《大象:Thinking in UML》这本书,可以系统地学习 UML 建模的核心知识和实践方法。

核心要点回顾

要点 核心内容
用例驱动 整个软件生产过程是用例驱动的,用例是需求、分析、设计、开发、测试、部署单元
边界意识 边界决定抽象层次,能否准确把握边界是做好需求分析和系统设计的关键
抽象层次 在合适的时候采用适当的抽象层次,同一抽象层次的内容应当放在一起
接口优先 接口是系统的灵魂,接口设计决定系统的可扩展性、可维护性和可测试性

UML 建模的价值

  1. 沟通工具:跨角色、跨团队的标准语言
  2. 思维工具:帮助理清复杂的业务关系
  3. 文档工具:比文字更直观的表达方式
  4. 设计工具:从需求到设计的映射桥梁

“抽象是面向对象的精髓所在,同时也是面向对象的困难所在。”

掌握 UML 建模,不仅仅是掌握画图技巧,更重要的是掌握一种思维方式——一种从现实世界抽象出软件模型的思维方式。这种思维方式,将帮助我们在复杂的软件开发中保持清晰的思路,设计出高质量的软件系统。


推荐阅读

  • 《大象:Thinking in UML(第2版)》- 谭云杰
  • 《UML 用户指南》- Grady Booch, James Rumbaugh, Ivar Jacobson
  • 《UML 精粹:标准对象语言简明指南》- Martin Fowler
  • 《设计模式:可复用面向对象软件的基础》- GoF

持续学习,持续实践! 📚