← 返回学习笔记

Lecture 4:软件设计与实现

408 学习笔记:Lecture 4:软件设计与实现。保留原有知识内容、公式与图示;有对应原件时提供查看和下载入口。

本页目录

描述:本节整理模块化、抽象、信息隐藏和模块独立性,完整转写耦合与内聚的等级次序;进一步说明 UML 顺序图的生命线、消息和激活,并按课件借书示例还原 18 条交互,最后总结类图、类关系及边界类/控制类/实体类识别方法。

4.1 模块与设计原则

4.1.1 模块

模块是具有独立名称、明确输入输出和特定功能的程序实体。它可以表现为函数、类、包、组件、服务或子系统。

良好模块应具有:

  • 清晰而单一的职责。
  • 最小且稳定的接口。
  • 隐藏的内部实现。
  • 可独立理解、测试、修改和复用的边界。

4.1.2 软件模块化

把复杂系统分解为若干职责明确、通过接口协作的模块,以控制复杂度并支持并行开发、测试和维护。

分解并非越细越好:模块过大难以理解,过小则接口和通信成本增加。应按职责、变化原因和信息边界划分。

4.1.3 抽象

抽象关注对象或模块“是什么、能做什么”,暂时忽略不影响当前层次的实现细节。

  • 数据抽象:规定数据及其允许操作。
  • 过程抽象:用一个名称代表一组步骤。
  • 控制抽象:隐藏控制流程细节,如迭代器或事件机制。

4.1.4 信息隐藏

模块只公开完成协作所需的接口,把容易变化的设计决策、数据表示和算法封装在内部。其他模块不能依赖这些秘密,从而减少修改传播。

4.1.5 模块独立性

模块独立性表示一个模块只完成相对独立的功能,并尽量少依赖其他模块。衡量的两个核心指标是:

  • 耦合:模块之间连接和依赖的紧密程度,越低越好。
  • 内聚:一个模块内部各元素为同一职责协作的紧密程度,越高越好。

目标是:

$$ \text{高内聚}+\text{低耦合}\Rightarrow\text{较强模块独立性}. $$

4.2 耦合等级

课件图从左到右耦合逐渐增强、模块独立性逐渐减弱:

无直接耦合 < 数据耦合 < 标记耦合 < 控制耦合 < 外部耦合 < 公共耦合 < 内容耦合
独立性强 ------------------------------------------------------> 独立性弱
类型 含义 例子或问题
无直接耦合 两模块没有直接关系,通过上层协调或完全独立 最弱耦合
数据耦合 只通过简单参数传递必要数据 传入订单号而非整个全局对象
标记耦合 传递复合结构,但接收方只使用其中一部分 传整个记录只读取一个字段
控制耦合 传递控制标志,决定另一个模块内部逻辑 mode=true 决定执行分支
外部耦合 共同依赖外部规定的协议、设备接口或文件格式 两模块都依赖特定通信协议
公共耦合 多个模块访问同一全局数据区 共享全局变量,修改影响难追踪
内容耦合 一个模块直接访问或修改另一模块内部实现 跳入内部代码、修改私有数据

NOTE 有些教材会因定义口径调整外部耦合与控制耦合的相对位置。考试应优先按题目所用教材分类;本课件给出的明确顺序如上。

降低耦合的方法:缩小接口、只传必要数据、消除全局状态、面向稳定抽象编程、通过事件或依赖注入隔离具体实现。

4.3 内聚等级

经典结构化设计教材通常把内聚分为七级;从左到右内聚逐渐降低、模块独立性逐渐减弱:

功能内聚 > 顺序内聚 > 通信内聚 > 过程内聚 > 时间内聚 > 逻辑内聚 > 偶然内聚
独立性强 -----------------------------------------------------> 独立性弱
功能单一 -----------------------------------------------------> 功能分散
类型 含义 例子
功能内聚 所有元素共同完成一个明确功能 计算订单总额
顺序内聚 一个元素的输出直接作为下一个元素的输入 读取原始数据、清洗后再计算统计量
通信内聚 多个操作使用或产生相同数据 读取一条记录并生成多个相关结果
过程内聚 元素必须按指定控制次序执行 先校验、再记录、再通知,但处理数据不一定相同
时间内聚 因在同一时间执行而组合 系统初始化或关闭时的一组不同操作
逻辑内聚 一组逻辑相似操作由控制参数选择其一 一个函数按标志执行多种输入操作
偶然内聚 元素之间几乎没有有意义联系 把杂项工具和无关处理放在同一模块

NOTE · 信息内聚的教材口径 有些教材在经典七级之外另列信息内聚:多个操作围绕同一数据结构组织,但通过各自独立的入口调用,例如抽象数据类型对同一对象提供增、删、改、查。它常被评价为较强内聚,但是否高于功能内聚、以及是否纳入统一排序,取决于教材体系;作答时应以题目给定口径为准,不能把它替换成经典七级中的“顺序内聚”。

提升内聚的关键是让模块围绕单一职责和单一变化原因组织,而不是只把代码放进同一文件。

4.4 顺序图

4.4.1 定义

顺序图(Sequence Diagram)是 UML 交互图,详细表示参与者实例、对象实例之间按时间先后发送消息的过程。

  • 横向表示不同参与者或对象。
  • 时间通常自上而下推进。
  • 重点是“谁在什么时候向谁发送什么消息”。

4.4.2 参与者、对象和系统边界

参与者位于系统边界外,代表与系统交互的角色。系统边界内放置边界对象、控制对象、实体对象或其他协作对象。

对象头通常写成 对象名:类名,也可以只写对象名或匿名类实例。

4.4.3 生命线与激活

  • 生命线:对象头下方的垂直虚线,表示该实例在一段时间内存在。
  • 激活条:生命线上的细长矩形,表示对象正在执行操作或等待嵌套调用返回。
  • 对象被创建时生命线从创建消息处开始;销毁时以 X 结束。

WARNING 课件说对象应“错落有致”并不严谨。通常参与者和已有对象放在图顶端横向排列;只有较晚创建的对象,其对象头和生命线才从较低位置开始。位置首先表达生命周期,不是为了美观随意错开。

4.4.4 消息

消息是对象之间通信的规格,既可传递调用等控制信息,也可携带参数和返回数据。

常见消息:

消息 含义 常见画法
同步调用 发送者等待被调用操作返回 实线加实心箭头
异步消息 发送后不等待接收者完成 实线加开放箭头
返回消息 返回结果或控制 虚线箭头
自消息 对象调用自身操作 回折到同一生命线
创建消息 创建新对象 箭头指向新对象头
销毁消息 终止对象生命线 箭头指向 X

复杂控制可用组合片段表达:alt 分支、opt 可选、loop 循环、par 并行。

4.4.5 课件“借书”顺序图完整转写

参与对象:

  • 图书管理员。
  • 借书界面类,边界类。
  • 借书控制类,控制类。
  • 读者类,实体类。
  • 借阅信息类,实体类。
  • 图书类,实体类。
  • 预约信息类,实体类。

图中的 18 条消息按时间顺序为:

  1. 图书管理员向借书界面录入读者信息。
  2. 借书界面请求借书控制类验证读者信息。
  3. 借书控制类调用读者类验证读者信息。
  4. 读者类返回验证成功。
  5. 借书控制类向借阅信息类查询读者借阅信息。
  6. 借阅信息类返回读者借阅信息。
  7. 借书控制类自调用,验证是否符合借阅条件。
  8. 借书控制类向借书界面返回并显示读者信息和借阅信息。
  9. 图书管理员向借书界面录入图书信息。
  10. 借书界面请求借书控制类验证图书信息。
  11. 借书控制类调用图书类,验证图书是否可借。
  12. 图书类返回“图书可借”。
  13. 借书控制类向借书界面返回并显示图书信息。
  14. 图书管理员在借书界面确认借阅。
  15. 借书界面请求借书控制类保存借阅信息。
  16. 借书控制类调用借阅信息类保存借阅信息。
  17. 借书控制类调用图书类修改图书状态。
  18. 借书控制类调用预约信息类删除相应预约信息。

该图体现典型分层协作:参与者只与界面交互,界面把业务请求交给控制类,控制类协调实体类完成校验和状态更新。

TIP 第 16 至 18 步共同构成一次借阅业务更新。真实系统还要考虑事务边界:保存借阅、修改图书状态、删除预约应保持一致,要么全部成功,要么整体回滚。

4.5 UML 与类图

4.5.1 UML

UML(Unified Modeling Language,统一建模语言)是一种标准化的可视化建模语言,用于说明、可视化、构造和记录软件密集系统的制品。

UML 是建模语言,不是完整的软件开发方法,也不规定团队必须采用哪一种过程模型。

常见 UML 图:

  • 用例图、活动图、状态机图。
  • 顺序图、通信图。
  • 类图、对象图、构件图、部署图、包图。

UML 模型是系统语义信息的整体;UML 图只是从某个视角呈现模型信息。一个模型可以由多张图表达,删除某一张图不一定等于删除模型中的全部语义。

4.5.2 类图

类图描述类、接口、属性、操作以及它们之间的静态关系,是系统逻辑视图和静态结构建模的重要组成部分。

一个类通常分三格:

  1. 类名。
  2. 属性。
  3. 操作或方法。

可见性符号:

  • +:public。
  • -:private。
  • #:protected。
  • ~:package。

4.5.3 类之间的关系

关系 含义 记法要点
依赖 Dependency 临时使用,供应者变化可能影响客户 虚线箭头
关联 Association 对象间较稳定的结构联系 实线,可写角色、导航性和多重性
聚合 Aggregation 较弱的整体-部分,部分可独立存在 整体端空心菱形
组合 Composition 强整体-部分,部分生命周期依赖整体 整体端实心菱形
泛化 Generalization 类之间的继承,is-a 实线空心三角指向父类
实现 Realization 类实现接口规定的契约 虚线空心三角指向接口

4.5.4 识别类的步骤

课件给出两步主线:

  1. 发现领域对象,从具体对象抽象出概念类。
  2. 在用例明确后,识别完成用例所需的对象,把具有相似属性和操作的对象归为类。

目标系统中的类常分为:

  • 边界类:处理参与者与系统之间的界面,如页面、API 适配器。
  • 控制类:协调某个用例的业务流程和对象协作。
  • 实体类:保存领域概念、业务数据和规则。

识别后还要分配职责、确定属性与操作、补充类关系和多重性,并检查是否存在上帝类、重复职责或不必要依赖。

4.6 顺序图与类图的配合

  • 类图描述系统有哪些类及其静态关系。
  • 顺序图描述某个场景中对象如何按时间协作。
  • 顺序图中的消息可帮助发现类所需的操作。
  • 类图中的关联和依赖应能支撑顺序图中的合法通信。

二者应相互校验:若顺序图要求对象发送某消息,而类图中接收类没有相应职责或关系,设计可能不一致。

4.7 常考辨析

4.7.1 高内聚是否必然导致低耦合

二者通常正相关但不是逻辑必然。应分别检查模块内部职责与模块之间依赖,目标同时是高内聚和低耦合。

4.7.2 公共耦合与外部耦合

  • 公共耦合是多个模块共享同一全局数据区。
  • 外部耦合是模块共同依赖外部接口、协议、设备或数据格式。

4.7.3 顺序图与活动图

  • 顺序图强调对象之间的消息时序。
  • 活动图强调业务或控制流程,可突出分支、并发和责任泳道。

4.7.4 UML 是否是一种开发过程

不是。UML 只提供建模符号和语义,可配合瀑布、迭代、敏捷等不同过程使用。

相关知识

本节复盘

  • 模块化通过抽象和信息隐藏控制复杂度,模块独立性由耦合与内聚共同衡量。
  • 耦合由弱到强为无直接、数据、标记、控制、外部、公共、内容耦合。
  • 经典七级内聚由强到弱为功能、顺序、通信、过程、时间、逻辑、偶然内聚;信息内聚属于另一种扩展口径。
  • 顺序图自上而下表达消息时序,核心元素包括参与者、对象、生命线、激活条和不同类型消息。
  • 借书顺序图通过边界类、控制类和实体类完成读者校验、图书校验及三项一致性更新。
  • 类图描述类、接口和静态关系;UML 是建模语言,不是软件开发过程。