3.2 体系结构设计
体系结构设计是结构化设计(SD)的核心环节,承接结构化分析(SA)的输出成果,核心目标是将需求阶段的数据流图(DFD)映射为可落地的软件模块层次结构,明确软件的模块组成、职责边界、调用关系与数据传递规则,最终输出标准化的模块结构图(SC图,Structure Chart),为后续详细设计、编码实现提供架构蓝图。
3.2.1 体系结构的启发式设计原则
启发式设计原则是软件工程领域数十年项目实践沉淀的架构设计质量准则,所有原则均围绕**高内聚、低耦合**的核心设计目标展开,是评判架构优劣、优化初始设计的核心依据。
前置核心概念:内聚与耦合
💡 核心定义
- 耦合:衡量不同模块之间相互依赖、关联的紧密程度,耦合度越低,模块独立性越强,架构越稳定。
- 内聚:衡量单个模块内部各个元素之间联系的紧密程度,内聚度越高,模块职责越单一,可维护性越强。
耦合等级对照表(从优到劣)
| 耦合类型 | 核心特征 | 设计建议 |
|---|---|---|
| 非直接耦合 | 两个模块无直接关联,仅通过主模块间接调度,无数据传递 | 最优,架构解耦的理想状态 |
| 数据耦合 推荐 | 模块间仅通过参数传递基础类型的业务数据 | 优先使用,是最安全的耦合方式 |
| 标记耦合 | 模块间通过参数传递复合数据结构(结构体/对象),仅使用部分字段 | 可接受,需避免传递冗余字段 |
| 控制耦合 | 一个模块通过传递控制信号,控制另一个模块的内部执行逻辑 | 尽量避免,会破坏模块封装性 |
| 外部耦合 | 多个模块共同依赖同一个全局外部资源(文件/硬件接口) | 限制使用,需统一收口管理 |
| 公共耦合 | 多个模块共同访问同一个全局公共数据域(全局变量/共享内存) | 严格限制,仅用于不可拆分的全局数据 |
| 内容耦合 | 一个模块直接访问/修改另一个模块的内部数据、代码,或直接跳转进入模块内部 | 严格禁止,完全破坏结构化设计规则 |
内聚等级对照表(从优到劣)
| 内聚类型 | 核心特征 | 设计建议 |
|---|---|---|
| 功能内聚 推荐 | 模块内所有元素仅为完成同一个单一功能存在,缺一不可 | 最优,是结构化设计的核心追求 |
| 顺序内聚 | 模块内处理元素与同一功能强相关,且必须顺序执行,前序输出为后序输入 | 优秀,可保留 |
| 通信内聚 | 模块内所有元素都操作同一个数据集,或生成同一个输出结果 | 良好,可接受 |
| 过程内聚 | 模块内处理元素相关,且必须按照特定的流程顺序执行 | 中等,尽量优化 |
| 时间内聚 | 模块内所有功能都在同一时间窗口内执行(如系统初始化、资源释放) | 较差,仅用于时序强相关的场景 |
| 逻辑内聚 | 模块内功能仅逻辑上相关,通过参数判断选择执行,功能本身无关联 | 差,必须优化拆分 |
| 偶然内聚 | 模块内元素无任何关联,仅偶然被放在一起 | 最差,严格禁止 |
核心启发式设计原则
1. 模块功能完善性原则
一个合规的模块必须具备输入、加工、输出三个完整部分,模块的所有输入数据必须被加工逻辑使用,所有输出必须有对应的输入来源,无冗余输入、无无效输出、无缺失逻辑。
⚠️ 常见错误
模块仅接收输入但无输出,或传递了大量未使用的冗余参数,会导致模块职责模糊、维护成本升高。
2. 模块规模适中原则
单个模块的代码行数建议控制在50-100行,最大不超过200行,可在一屏内完整展示。
- 模块过大:说明职责过载、内聚度低,需拆分;
- 模块过小:会导致系统模块数量爆炸,调用关系复杂,耦合度升高,需合并。
3. 模块结构的深度、宽度、扇入、扇出适中原则
| 指标 | 定义 | 设计准则 |
|---|---|---|
| 深度 | 模块结构图的总层次数,反映系统的规模与复杂程度 | 与系统规模匹配,避免层次过深导致调用链路冗长 |
| 宽度 | 同一层次的最大模块数量,反映系统的横向复杂度 | 避免宽度过大,导致顶层模块调度逻辑过载 |
| 扇出 | 一个模块直接调用的下级模块数量 | 最优区间3-5,最大不超过7;扇出过大需拆分,长期为1需合并 |
| 扇入 | 一个模块被多少个上级模块直接调用 | 不破坏单一职责的前提下,扇入越大越好,代表模块复用度高 |
4. 模块的作用域必须完全包含在控制域之内原则
💡 核心定义
- 控制域:模块本身,以及它所有直接、间接下属模块的集合(模块可调度的所有模块范围)。
- 作用域:受模块内一个判定结果影响的所有模块的集合(模块内的判断逻辑会影响执行的模块范围)。
核心准则:模块的作用域必须100%包含在控制域之内,最优设计是:受判定影响的模块,为判定所在模块本身或其直属下级模块。
⚠️ 重难点风险
作用域超出控制域,会导致模块间出现强制的控制耦合,模块逻辑与外部强绑定,出现问题难以定位、需求变更难以修改,是架构设计的高频严重缺陷。
5. 降低模块接口的复杂程度与冗余度原则
模块接口是耦合的核心来源,需遵循以下规则:
- 接口参数数量少、含义明确,与模块功能强相关,无冗余参数;
- 参数传递顺序、类型保持统一规范,避免相似功能模块出现接口不一致的问题;
- 优先传递基础类型数据,避免传递与模块功能无关的复合数据结构。
6. 单入口、单出口的模块设计原则
这是结构化设计的强制性准则:每个模块必须仅有一个入口、一个出口,仅能从模块顶部进入、从模块底部退出,严禁从模块中间进入、跳转,严禁使用goto语句跨模块跳转,严禁出现内容耦合。
7. 模块功能可预测,避免过度限制原则
- 功能可预测:模块行为具备确定性,相同输入必须产生固定输出,禁止用内部不可控的静态变量、全局状态影响模块输出;
- 无过度限制:不对模块功能做不必要的硬编码限制(如固定死缓冲区大小、固定死处理条数),避免降低模块复用性。
3.2.2 面向数据流的设计方法
面向数据流的设计方法(又称结构化设计方法SD),是与结构化分析(SA)无缝衔接的标准化架构设计方法,核心是通过固定的映射规则,将需求阶段的数据流图(DFD)转化为标准化的模块结构图(SC图),彻底解决架构设计无规范、无标准的问题。
前置基础:模块结构图(SC图)核心符号
| SC图符号 | 符号含义 | 设计规范 |
|---|---|---|
| 矩形框 | 功能模块 | 框内标注模块名称,必须直接体现模块的核心功能 |
| 带箭头的实线 | 模块调用与数据传递 | 箭头指向被调用模块,线上标注传递的业务数据名称 |
| 带箭头的虚线 | 控制信息传递 | 箭头指向被调用模块,线上标注传递的控制信号名称 |
| 菱形 | 条件判断 | 标注在调用模块上,代表根据条件选择调用下级模块 |
| 弧形箭头 | 循环调用 | 标注在调用模块上,代表循环调用多个下级模块 |
核心前提:数据流的两种典型类型
DFD中的数据流分为两种核心类型,不同类型对应完全不同的映射规则,是架构设计的核心依据。
| 数据流类型 | 核心特征 | 核心锚点 | 典型业务场景 |
|---|---|---|---|
| 变换型数据流 | 线性处理逻辑,数据流可清晰划分为输入流、变换中心、输出流三部分;数据沿一条路径进入系统,经核心加工后沿一条路径离开系统 | 变换中心:数据流的性质发生根本性改变的加工节点 | 学生成绩管理:成绩录入→加权计算→排名统计→报表输出 |
| 事务型数据流 | 分支处理逻辑,数据流沿输入路径到达核心节点后,根据事务类型选择多条执行路径中的一条,核心特征是「一对多」的分支调度 | 事务中心:接收输入数据、识别事务类型、分发事务分支的调度加工节点 | 银行ATM系统:身份验证后,选择取款/查询/转账/改密码等分支 |
📌 补充说明
绝大多数商用系统的DFD,都是变换型+事务型的混合结构,设计时需先识别主结构类型,再处理局部的子结构。
面向数据流设计的标准化全流程
步骤1:复审并精化需求DFD
对需求阶段输出的DFD进行完整性、正确性、一致性复审,去除冗余加工、合并过于琐碎的原子加工,确保DFD完全贴合需求规格说明,无歧义、无遗漏,为后续映射提供合规的输入。
步骤2:判定DFD类型,定位核心锚点
- 变换型数据流:识别输入流、输出流的边界,精准定位变换中心;
- 事务型数据流:识别事务接收路径、事务活动路径,精准定位事务中心。
步骤3:执行标准化映射,生成初始SC图
映射规则1:变换型数据流映射
- 顶层与第一层分解:
- 顶层:设计唯一的主控模块,负责协调整个系统的执行流程;
- 第一层:分解为3个核心模块,分别对应输入流、变换中心、输出流,即输入控制模块、变换控制模块、输出控制模块。
- 下层逐层分解:自顶向下,将DFD中的每个加工节点,映射为对应控制模块的下层子模块,直到每个模块达到功能内聚、规模适中的要求。
映射规则2:事务型数据流映射
- 顶层与第一层分解:
- 顶层:设计唯一的主控模块,负责协调整个事务流程;
- 第一层:分解为3个核心模块,即事务接收模块、事务调度中心模块、结果输出模块。
- 下层逐层分解:
- 事务接收模块:映射DFD中事务输入、校验的相关加工,分解为对应的子模块;
- 事务调度中心模块:为每一种独立的事务类型,设计对应的事务处理子模块,确保分支独立;
- 结果输出模块:映射DFD中结果格式化、输出的相关加工,分解为对应的子模块。
步骤4:基于启发式设计原则优化架构
对生成的初始SC图进行优化调整,解决模块耦合过高、内聚过低、结构失衡、作用域越界等问题,最终得到高内聚、低耦合的最终软件体系结构。
3.2.3 事务型体系结构设计实例
本实例以高校图书管理系统-读者服务模块为业务背景,完整落地事务型体系结构设计的全流程,实现从需求DFD到最终SC图的完整映射与优化。
实例业务需求说明
读者服务模块的核心业务流程:
- 读者刷校园卡、输入密码,系统完成读者身份合法性校验;
- 校验通过后,读者可选择4类独立的事务操作:借书、还书、图书信息查询、个人借阅记录查询;
- 对应事务操作执行完成后,系统统一格式化处理结果,输出到读者操作终端。
步骤1:输出精化后的DFD
0层DFD(顶层数据流图)
1层DFD(细化加工节点)
步骤2:判定DFD类型,定位核心锚点
- 主结构类型:典型的事务型数据流
- 核心事务中心:加工节点2「事务类型判断」,完全符合事务中心的核心特征:接收输入数据、识别事务类型、分发调度对应的事务分支
- 局部结构说明:前端的身份验证、后端的结果输出为局部变换型结构,设计时先处理主事务结构,再完善局部变换结构
步骤3:映射生成初始SC图
严格遵循事务型数据流的映射规则,自顶向下逐层分解,生成初始模块结构图:
- 第 1 张:主概览图(只放顶层模块,超宽松)
- 第 2 张:子图 1(验证模块细节)
- 第 3 张:子图 2(事务处理细节)
- 第 4 张:子图 3(输出模块细节)
步骤4:基于启发式原则优化架构
初始设计的问题识别与优化方案
| 初始设计问题 | 违反的启发式原则 | 优化方案 |
|---|---|---|
| 事务调度中心模块扇出为4,处于最优区间,但各事务模块的校验逻辑存在重复代码 | 模块复用性不足、扇入可提升 | 提取公共的「图书基础信息校验模块」「读者权限校验模块」,被多个事务模块调用,提升模块扇入与复用度 |
| 借书、还书模块直接操作数据库,接口复杂,耦合度高 | 模块接口复杂度高、外部耦合 | 新增统一的「数据库操作收口模块」,所有数据库读写均通过该模块完成,降低耦合 |
| 身份验证模块的「验证失败」判定,直接调用同级的结果输出模块 | 作用域超出控制域 | 将结果输出模块的错误提示子模块,下沉到身份验证模块的控制域内,确保作用域完全包含在控制域中 |
优化后的最终SC图(核心结构)
💡 实例设计合规性说明
- 整体为清晰的层次化结构,严格遵循自顶向下的调用规则,无反向调用、无同级违规调用;
- 事务中心仅负责事务调度,不参与具体业务处理,职责单一,符合功能内聚要求;
- 公共逻辑统一收口,模块复用度高,耦合度低,完全符合高内聚、低耦合的核心设计目标;
- 所有模块的作用域均完全包含在控制域之内,无违规设计。
📖 拓展练习
基于本实例的业务需求,新增「读者挂失/解挂」「预约图书」两类事务分支,完成体系结构设计,输出优化后的完整SC图,并基于启发式设计原则说明设计合规性。