软考架构——系统分析与设计:结构化与面向对象
一、系统分析与系统设计
系统分析 阶段是应用系统思想和方法,把复杂的对象分解为简单的组成部分,找出这些部分的基本属性和彼此之间的关系的过程,其基本任务是系统分析师和用户在充分了解用户需求的基础上,把双方对新系统的理解表达为 系统需求规格说明书。
系统设计 的目标是根据系统分析的结果,完成系统的构建过程。其主要目的是绘制系统的蓝图,权衡和比较各种技术和实施方法的利弊,合理分配各种资源,构建新系统的详细设计方案和相关模型,指导系统实施工作的顺利开展。系统设计的主要内容包括 概要设计 和详细设计。
通俗点说,系统分析解决“做什么 ”的问题,主要由系统分析师完成;系统设计解决“ 怎么做”的问题,主要由系统架构师完成。
结构化和面向对象这两种方法,在系统分析和设计中都有应用,以下分别展开介绍。
二、结构化方法
结构化方法 ,也称为 面向功能的软件开发方法 或面向数据流的软件开发方法 ,提出了一组提高软件结构合理性的准则,如分解与抽象、模块独立性、信息隐蔽等。针对软件生存周期各个不同的阶段,它有结构化分析(SA)、结构化设计(SD) 和结构化编程 (SP) 等方法。
(一)结构化分析
结构化分析(Structured Analysis,SA) 的基本思想是自顶向下,逐层分解,把一个大问题分解成若干个小问题,每个小问题再分解成若干个更小的问题。经过逐层分解,每个最底层的问题都是足够简单、容易解决的,于是复杂的问题也就迎刃而解了。
SA 建立的模型的核心是 数据字典。围绕这个核心,有三个层次的模型:
- 数据模型 :描述系统的实体对象以及实体之间的联系,通常以 实体关系图(ER 图) 表示,
- 功能模型 :描述系统各功能模块对数据的处理,通常以 数据流图(DFD) 表示
- 行为模型 :描述系统的状态以及影响状态的事件,通常以 状态转换图(STD) 表示
1. 数据流图
数据流图(Data Flow Diagram,DFD)的核心是数据流。DFD 从应用系统的数据流着手,以图形方式刻画和表示一个具体业务系统中的数据处理和流动。
DFD 由 4 种基本元素 (模型对象) 组成:
- 数据流(Data Flow):用一个箭头描述数据的流向,箭头上标注的内容可以是信息说明或数据项。
- 处理 / 加工(Process):表示对数据进行的加工和转换,在图中用矩形框表示,指向处理的数据流为该处理的输入数据,离开处理的数据流为该处理的输出数据。
- 数据存储 :表示系统内部用数据库形式(或者文件形式) 存储的数据,在图中用上下各一条线段来表示,对其进行的存取操作分别以指向或离开数据存储的箭头表示。
- 外部实体:也称为数据源或者数据终点,描述系统数据的提供者或者数据的使用者,在图中用圆角框或者平行四边形框表示。
使用 DFD 建立功能模型,主要通过 DFD 自顶向下的 逐层分解 来实现:
首先创建顶层 DFD 图。顶层 DFD 是描述系统最高层结构的 DFD,它的特点是将整个待开发的系统表示为一个加工,将所有的外部实体和进出系统的数据流都画在一张图中。
然后自顶向下逐层分解,得到最终的 DFD 层次结构图。层次结构图中的上一层是下一层的抽象,下一层是上一层的细化,而最后一层中的每个处理都是一个具体可实现的描述,即一个处理模块仅描述和解决一个问题。
在 DFD 分解过程中,要遵循数据流图的 平衡原则:
- 父图与子图的平衡,即上下级数据流图之间数据流的完整性和一致性
- 父图中的数据流必须在子图中有所对应:每一个在父图中出现的数据流,在子图中也必须出现。
- 子图的输入和输出数据流必须与父图中该过程的输入和输出数据流相匹配:这意味着子图的总输入和总输出必须与父图中对应过程的输入和输出完全一致。
- 子图内部平衡
- 一个处理至少有一个输入流和一个输出流。只有输入没有输出的处理称为 黑洞 ;只有输出没有输入的处理称为 奇迹 ;输入不足以产生输出的处理称为 灰洞。
- 一个存储必须有流入的数据流和流出的数据流。
- 一个数据流至少有一端是处理端。
2. 状态转换图
状态转换图(简称状态图,State Transform Diagram,STD)通过描绘系统的状态及引起系统状态的事件来表示系统的行为。
STD 中定义的状态主要有 3 种:
- 初态(初始状态):用黑圆点表示,一个 STD 只有一个初态。
- 终态(最终状态):用黑圆点外加一个圆表示,一个 STD 可以没有终态,也可以有一个或多个终态。
- 中间状态:用圆角矩形表示,状态之间的转换用箭头表示。
3. 实体关系图
实体关系图(Entity Relation Diagram,ERD)用于描述系统的各种实体及其之间的关系,主要包含三个基本元素:
- 实体:系统中的对象或概念,用矩形框表示。
- 属性:实体具有的特性,用椭圆形表示。
- 联系:用菱形框表示,通过连线与有关的实体相连,在连线上注明对应关系(1:1,1:n,m:n)。
使用 ER 图建立数据模型,主要采用自底向上的策略,首先设计局部 ER 图,然后将各个局部 ER 图合并起来形成全局 ER 图,最后对全局 ER 图进行优化。
4. 数据字典
数据字典是描述数据信息的集合,是对系统中使用的所有数据元素的定义的集合,主要目的是对系统中出现的条目给出严密一致的解释。在结构化分析中,数据流图上所有元素的定义和解释的文字集合就是数据字典。
数据字典包含 6 类元素:
- 数据项:数据流图中数据块的数据结构中的数据项说明,数据项是不可再分的数据单位。
- 数据结构:数据流图中数据块的数据结构说明,一个数据结构可以由若干个数据项和若干个数据结构组成。
- 数据流:数据流图中流线的说明,数据流是数据结构在系统内传输的路径。
- 数据存储:数据流图中数据块的存储特性说明,是数据结构停留或保存的地方。
- 加工逻辑:数据流图中功能块的说明,数据字典中只需要描述处理过程的说明性信息。
- 外部实体:数据流图中位于系统外部的实体,通常是数据流的源点或终点。
(二)结构化设计
结构化设计(Structured Design,SD) 是一种面向数据流的设计方法,它以 SRS 和 SA 阶段所产生的数据流图和数据字典等文档为基础,是一个自顶向下、逐步求精和模块化的过程。
SD 方法的基本思想是 将软件设计成由相对独立且具有单一功能的模块组成的结构,分为概要设计和详细设计两个阶段:
- 概要设计:确定软件系统的结构,对系统进行模块划分,确定每个模块的功能、接口和模块之间的调用关系。
- 详细设计:为每个模块设计实现的细节。
SD 包括四项设计活动:数据设计、软件结构设计、接口设计(人机界面设计)、过程设计。SD 以 SA 为基础,它们的关系如图所示:
SD 将系统划分为可自由组合、分解、和变换的功能模块,模块划分应遵循如下原则:
模块大小适中
模块扇入和扇出合理,设计良好的软件结构通常顶层扇出比较大,中间扇出较少,底层模块则有较大扇入。
- 扇出是指该模块直接调用的下级模块个数。扇出大表示模块复杂度高,需要添加中间层的控制模块。
- 扇入是指直接调用该模块的上级模块个数。扇入大表示模块复用程度高。
深度和宽度适当,深度表示模块层数,宽度表示同一层模块总数的最大值。
信息隐蔽,采用封装技术隐藏程序模块实现细节,使模块接口尽可能简单。
高内聚,低耦合
- 耦合度从低到高
耦合度 描述 非直接耦合(低) 两个模块之间没有直接关系,它们之间的联系完全是通过主模块的控制和调用来实现的 数据耦合 模块借助参数表传递简单数据 标记耦合 模块通过参数表传递记录信息(数据结构) 控制耦合 模块之间传递的信息中包含用于控制模块内部逻辑的信息 通信耦合 一组模块共用了一组输入信息,或者它们的输出需要整合以形成完整数据,即共享了输入或输出 公共耦合 多个模块都访问同一个公共数据环境,公共数据环境可以是全局数据结构、共享的通信区、内存的公共覆盖区等 内容耦合(高) 一个模块直接访问另一个模块的内部数据;一个模块不通过正常入口转到另一个模块的内部;两个模块有一部分程序代码重叠;一个模块有多个入口等 - 内聚度从高到底
内聚类型 描述 功能内聚(高) 完成一个单一功能,各个部分协同工作,缺一不可 顺序内聚 处理元素相关,而且必须顺序执行 通信内聚 所有处理元素集中在一个数据结构的区域上 过程内聚 处理元素相关,而且必须按特定的次序执行 时间内聚 所包含的任务必须在同一时间间隔内执行 逻辑内聚 完成逻辑上相关的一组任务 偶然内聚(低) 完成一组没有关系或松散关系的任务
三、面向对象方法
面向对象 (Object-Oriented,OO) 开发方法 将面向对象的思想应用于软件开发过程中,主张参照人们认识一个现实系统的方法,完成分析、设计与实现一个软件系统,强调最终建立的系统能映射问题域,使得系统中的对象、以及对象之间的关系能够如实地反映问题域中固有的事物及其关系。
面向对象开发方法是 以用例驱动的、以体系结构为中心的、迭代的和渐增式的开发过程,主要包括需求分析、系统分析、系统设计和系统实现 4 个阶段。但是,各个阶段的划分不像结构化开发方法那样清晰,而是在各个阶段之间迭代进行的。
(一)面向对象分析
面向对象的分析方法 (Object-Oriented Analysis,OOA) 运用面向对象方法分析问题域,正确认识问题域中的事物及它们之间的关系,找出描述问题域和系统功能所需的类和对象,定义它们的属性和职责,以及它们之间所形成的各种联系。
使用 OOA 时,包含建立用例模型与分析模型两大步骤:
1. UML 统一建模语言
UML(Unified Modeling Language,统一建模语言)是面向对象的标准化建模语言,其总体结构如图所示:
在 UML 中,有两种类型的图:
- 结构图 :也称 静态图,用来描述事物之间的关系,包括类图、对象图、组件图和部署图等。
- 行为图 :也称 动态图,用来描述参与者和用例之间的交互,或者描述参与者如何使用系统,包括用例图、顺序图、活动图、状态图和通信图等。
(1) 类图
类图描述类、接口、协作及它们之间的关系。在系统分析阶段,通过类图来表述问题域的对象和对象之间的联系。
一个类包含三个部分:类名、属性、方法。类与类之间有 6 种,分别的含义与表达方式如下:
这六种关系由强到弱依次为:继承 = 实现 > 组合 > 聚合 > 关联 > 依赖。
组合与聚合的区别在于生命周期的差别:组合关系具有相同的生命周期 ,“部分”会随着“整体”的创建而创建,也随着“整体”的消亡而消亡; 聚合关系意味着好聚好散,“部分”与“整体”生命周期可以不同。
在如下示例中,Heart 和 People 是组合关系,People 和 PeopleGroup 是聚合关系:
(2) 用例图
用例模型通常以用例图表示,用例图由 4 个元素组成:
- 参与者(Actor):系统交互的所有事物,该角色不仅可以由人承担,还可以是其他系统和硬件设备,甚至是系统时钟。在图中用一个小人表示。
- 用例(Use Case):外部可见的系统功能单元,对系统提供的服务进行描述。在图中用椭圆表示。
- 系统边界(System Boundary):系统与系统之间的界限。在图中用方形容器 + 系统名称表示。
- 用例之间的关系:分为 包含、扩展、泛化 三种。
- 包含与扩展的区别:包含用例是无条件执行,即不论如何都会执行;扩展用例是有条件执行,即满足某种条件才会执行。
- 扩展与泛化的区别:泛化强调的是继承和重用,执行父用例,实际上是执行某一个子用例;扩展强调的是条件和可选性,在基础用例执行后,满足某个条件再执行扩展用例。
(3) 顺序图(时序图)
顺序图代表了一个相互作用、以时间为次序的对象之间的通信集合。顺序图的主要用途之一是为用例进行逻辑建模,任何用例模型都可以使用顺序图进一步阐明和实现。
顺序图的主要元素包括:
- 对象:系统中参与交互的实例。每个对象通常对应于类的一个具体实例,并在图中以矩形框加上对象名称和类名的形式表示。
- 生命线:表示对象在交互过程中的存在时间。它以从对象框向下延伸的虚线表示。
- 激活:表示对象在特定时间段内执行某个操作或方法。它通常以一个细长的矩形条覆盖在生命线上,显示该对象在此期间处于活动状态。
- 消息:表示对象之间传递的信息或调用的方法,可分为同步消息、异步消息、返回消息三种类型。消息用带箭头的实线或虚线表示,箭头指向接收消息的对象在,不同消息类型用不同箭头样式表示。
- 交互片段:用于封装交互图中的片段,并可对片段施加一定的操作(如选择、循环、并行等),从而支持复杂的交互建模。
(4) 通信图(协作图)
通信图显示了对象间的联系以及对象间发送和接收的消息。通信图与顺序图在语义上时等价的,可以相互转换,二者的区别在于:
- 顺序图展示了对象之间如何相互协作来完成某一项功能,强调各个对象按照 时间顺序 进行交互的过程。
- 通信图也描述了对象之间如何相互协作来完成某一项功能,但侧重于强调参与交互的对象的 组织关系。
通信图的主要元素包括:
- 类角色:在特定交互中对象所扮演的角色。每个类角色对应于类图中的一个类,但在通信图中,类角色强调对象在交互过程中的功能和责任。
- 关联角色:在通信图中对象之间的关系角色。每个关联角色通常对应于类图中定义的一个关联,并指定了对象在该关联中的具体角色或职责。
- 对象:系统中参与交互的实例。每个对象通常对应于类的一个具体实例,并在图中以矩形框加上对象名称和类名的形式表示。
- 链:对象间发送消息的路径,用来在通信图中关联对象。在图中由一个或多个相连的线(直线或弧线)形成,链的两端是消息发送者和消息接收者。
- 消息:表示对象之间传递的信息或调用的方法。在图上通过沿着链的箭头,以及箭头上添加消息名和消息编号来表示。消息编号用来表示消息的先后次序。
(5) 活动图
活动图将业务流程或其他计算的结构展示为内部一步步的控制流和数据流,主要用于描述某一方法、机制或用例的内部行为。
活动图的主要元素包括:
- 起点:活动起始点,用实心圆表示,有且只有一个。
- 终点:活动结束点,用同心圆表示,可能有多个。
- 活动:对象执行的具体操作,用圆角矩形表示,活动名用动宾短语描述。
- 判断(决策点):流程产生分支的地方,用菱形表示。
- 泳道:表示参与活动的不同对象,每个用到表示一个参与者的职责范围。用矩形划分区域,每个对象的活动只能画在对应的泳道。
- 控制流:将不同的活动按顺序连接起来,用带箭头的连线表示。
- 分叉 / 合并:分叉将控制流分为两个或多个并发运行的分支;合并用于同步并发分支,以达到共同完成一项事务的目的。在活动图中,用一条水平或者垂直的小黑棒表示。
活动图与流程图的区别:
- 活动图支持复杂流程,包括并发行为;流程图不支持并发活动。
- 活动图面向对象,可以表示对象之间的交互;流程图面向过程,强调步骤之间的顺序和关系。
- 活动图多用于软件工程和系统建模,适用于需求分析和系统设计;流程图多用于业务管理,适合描述工作流程。
2. 4+1 视图
RUP 中的 4+1 架构视图是 UML 在软件工程中的优秀实践。4+1 架构模型从不同的视角为系统架构建模,形成不同的视图:
- 用例视图:从用户角度,描述系统的功能,通常以用例图、场景图表示。
- 逻辑视图:从系统分析和设计人员角度,描述系统的组件和模块之间的关系,通常以类图、对象图表示。
- 实现视图:从开发人员角度,描述系统代码结构,通常以组件图、包图表示。
- 进程视图:从系统集成人员角度,描述系统运行时各对象的行为与交互,通常以状态图、活动图、时序图表示。
- 部署视图:从系统工程师角度,描述系统的软件到硬件的映射和分布关系,通常以部署图表示。
(二)面向对象设计
面向对象设计(Object-Oriented Design,OOD)是将 OOA 所创建的分析模型转化为设计模型,其目标是定义系统构造蓝图。OOD 的基本思想包括抽象、封装、继承和多态。在 OOD 中,数据结构和在数据结构上定义的操作算法封装在一个类中。
1. 类的分类
OOD 中设计的类分为三种:
- 边界类(Boundary class):负责系统与外部世界的交互,通常是用户界面、API 接口或外部系统的通信接口。
- 控制类(Control class):负责处理系统的逻辑流程和业务规则,充当协调者,控制系统的运作。
- 实体类(Entity class):代表系统中的数据对象或业务对象,通常对应数据库中的表,是系统中需要长期保存的信息。
通俗来说:
- 边界类负责输入和输出,与用户或外部系统交互。
- 控制类负责逻辑控制,管理操作流程和业务规则。
- 实体类负责数据存储,代表系统中的业务对象和数据。
通过这种分类,我们可以更加清晰地分离系统中的不同职责,使系统设计更加模块化和可维护。
2. 设计原则
在 OOD 中,合理运用设计原则可以带来可维护性的提升。常用的 OOD 原则为:
原则 | 描述 |
---|---|
单一职责原则(S) | 每个类应该只有一个引起变化的原因,类的职责要单一 |
开闭原则(O) | 软件实体(类、模块、函数等)应该可以扩展,但不可修改 |
里氏替换原则(L) | 子类对象必须能够替换其基类对象,且保证程序的正确性,反之不一定成立 |
接口隔离原则(I) | 使用多个专门的接口,而不使用单一的总接口 |
依赖倒置原则(D) | 高层模块不应该依赖低层模块,二者都应该依赖抽象。抽象不应该依赖细节,细节应该依赖抽象。要针对接口编程,而不是针对实现编程 |
最少知识原则(迪米特法则) | 一个软件实体应当尽可能少地与其他实体发生相互作用 |
组合 / 聚合复用原则 | 多用组合或聚合关系来复用已有对象,少用继承关系 |
3. 设计模式
设计模式是前人经验的总结,它使人们可以方便地复用成功的设计和架构。当在特定的环境下遇到特定类型的问题,采用他人已使用过的一些成功的解决方案,一方面可以降低分析、设计和实现的难度,另一方面可以使系统具有更好的可复用性和灵活性。
常见的设计模式包含如下 3 大类共 23 种: