详细设计基础
什么是详细设计
- 具体模块的中层设计:OO来实现类的具体设计
- 具体模块中的对象/类的低层设计:数据结构+算法来实现具体的类
详细设计的输入:需求规格说明和体系结构设计
详细设计出发点
软件详细设计在软件体系结构设计之后进行,以需求开发的结果(需求规格说明和需求分析模型)和软件体系结构的结果(软件体系结构设计方案与原型)为出发点。
详细设计的上下文
详细设计阶段,软件工程师可以将需求和软件体系结构设计方案作为工作方向和框架,展开详细设计。
详细设计的目的是实现所有功能性需求和非功能性需求,需要以需求为驱动,细化设计框架的各个构件,使其能够满足各个细节的功能性需求与非功能性需求(而非仅仅是概要需求与关键性非功能需求)。详细设计的结果是能够指导程序员编程的详细设计文档和详细设计原型代码在详细设计文档中需要明确定义:
- 模块结构及其接口(如果有更细节的模块分解)
- 类结构、类的写作、类接口(面向对象分析方法)
- 控制结构与函数接口(结构化分析方法)
- 重要的数据结构和算法逻辑(如果有必要的话)
结构化详细设计
// todo
面向对象详细设计
面向对象设计的过程
- 设计模型建立
- 通过职责建立静态设计模型
- 抽象类的职责
- 抽象类之间的关系
- 添加辅助类
- 通过协作建立动态设计模型
- 抽象对象之间的协作
- 明确对象的创建
- 选择合适的控制风格
- 通过职责建立静态设计模型
- 设计模型重构
- 根据模块化的思想进行重构,目标为高内聚、低耦合
- 根据信息隐藏的思想重构,目标为隐藏职责与变更
- 利用设计模式重构
通过职责建立静态设计模型
职责 Responsibility
面向对象设计的思想:职责。数据信息和所能够做的事情就组成了这个自由数据个体的职责(数据职责 + 行为职责)。个体只是行使自己的职责,而遇到自己无法完成的事情,则会通过互相发送消息,要求其他个体来做他们能够做的事
- 行为职责一般通过方法来表现
- 数据职责一般通过属性来表示
- 类之间的协作也可能包含在内
Responsibility-Driven Decomposition
- 职责可能被表现为不同等级的抽象
- 职责可以被分解
- 高层次的职责会被分配给高层次的构件
- 职责分解是构件分解的基础:职责反映了行为和数据的义务,所以职责驱动的分解和函数分解不太一样
Responsibility Heuristics(职责启发式)
- 分配职责能够实现高内聚、低耦合
- 注意模块的职责不要重叠
- 将行为和数据放到某个模块中时要确保它们是符合这个模块的职责的
设计类图的绘制
设计类图与概念类图相似,图例相同,不同的是概念类的属性可能没有类型约束,且不一定是全部的详细属性,概念类图也不会显式标记类的行为,即概念类不会包含明确的方法
关系类型 | 关系 | 关系短语 | 解释 | 多重性 | UML表示法 |
---|---|---|---|---|---|
General | 依赖 | A use a B | 被依赖的对象只是被作为一种工具使用,其引用并不背另一个对象持有 | 无 | 虚线鱼骨箭头 |
Object Level | 普通关联 | A has a B | 某个对象会长期持有另一个对象的引用。关联的两个对象彼此间没有任何强制性的约束 | A: 0..*; B: 0..* | 实线鱼骨箭头(双向没有箭头) |
聚合 | A owns B | 它暗含着一种集合所属关系。被聚合的对象还可以再被别的对象关联,所以被聚合对象是可以共享的 | A: 0..1; B: 0..*; 集合可以为空 | 实线空心菱形箭头 | |
组合 | B is a part of A | 它既要求包含对象对被包含对象的拥有,又要求包含对象与被包含对象的生命期相同。被包含对象还可以再背别的对象关联,所以被包含对象是可以共享的。然而绝不存在两个包含对象对同一个被包含对象的共享 | A: 0..1; B: 1..1; 整体存在,部分一定存在 | 实线实心菱形箭头 | |
Class Level | 继承 | B is A | 继承是一种非常强的关系。子类会将父类所有的接口和实现都继承回来。但是,也可以覆盖父类的实现 | 无 | 实线空心三角箭头 |
实现 | B implements A | 类实现接口,必须实现接口中的所有方法 | 无 | 虚线空心三角箭头 |
添加辅助类
辅助类可能包括以下几种:
- 接口类
- 记录类(数据类)
- 启动类
- 控制器类
- 实现数据类型的类
- 容器类
通过协作建立动态设计模型
协作 Collaboration
如何设计对象之间的协作,一般有两种方法:
- 从小到大,将对象的小职责聚合形成大职责
- 从大到小,将大职责分配给各个小对象。
顺序图
可以使用顺序图来表示对象之间的协作。顺序图主要分为两个部分
- 对象本身:需要标明对象的生命周期
- 对象之间的消息流:表示何时哪个对象向另一个对象发送了什么消息
消息类型 | 解释 | 图示 |
---|---|---|
同步消息 | 发送者等候直到消息返回 | 实线实心三角箭头 |
异步消息 | 发送者再消息发送后继续执行 | 实线鱼骨箭头 |
同步消息返回 | 接受同步消息者执行结束后,返回消息给发送者 | 虚线鱼骨箭头 |
明确对象的创建
场景 | 创建地点 | 创建时机 | 备注 |
---|---|---|---|
唯一属于某个整体的密不可分的一部分(组合关系) | 整体对象的属性定义和构造方法 | 整体对象的创建 | 例如,销售的业务逻辑对象由销售页面对象创建 |
被某一对象记录和管理(单向被关联) | 关联对象的方法 | 业务方法的执行中对象的生命周期起始点 | 例如,连接池管理对象需要负责创建连接池对象 |
创建所需的数据被某个对象所持有 | 持有数据的对象的业务方法 | 业务方法的执行中 | 也可以考虑在此持有数据对象不了解创建时机时,由别的对象创建,由它来初始化 |
被某个整体包含(聚合关系) | 整体对象的业务方法(非构造方法) | 业务方法的执行中 | 如果某个对象有多个关联,优先选择聚合关联的整体对象。如果某个对象有多个聚合关联的整体对象,则考查整体对象的高内聚和低耦合来决定由谁创建 |
其他 | 通过高内聚和低耦合来决定由谁创建 |
选择合适的控制风格
- 集中式
- 委托式
- 分散式
集中式
- 集中式的控制风格可以很清楚的知道决策是在哪里做出的
- 可以很容易的更改决策的过程
- 控制器可能会变得臃肿 - 大,复杂且难以理解、维护、测试等
- 控制器可能将其他构件视为数据仓库对待
- 增加了耦合
- 失去了信息隐藏
委托式
详细设计文档描述和评审
// todo
Reference
- 南京大学软件学院2022春季学期《软件工程与计算二》