包括概要设计和详细设计。

一、概述

系统设计师系统分析的延伸与拓展。系统分析阶段解决“做什么”的问题,而系统设计阶段解决"怎么做"的问题。

系统设计阶段又称为物理设计阶段,任务是根据系统规格说明书中规定的功能要求,考虑实际条件,具体设计实现逻辑模型的技术方案,即设计新系统的物理模型。相对地,系统分析确定系统的基本目标和逻辑模型,因此又称为逻辑设计阶段。

实际上,系统分析与系统设计之间,还有一个阶段,就是系统架构设计。系统设计解决的是系统业务逻辑本身的物理设计问题,但业务逻辑不是运行在空中楼阁,它需要实实在在的支撑。架构设计就是负责提供这个支撑。比如说,同样处理这些业务,我们既可以采用单体架构,也可以采取SOA或者微服务架构;既可以是CS,也可以是BS,就看怎么衡量。

系统设计的内容包括概要设计和详细设计。

二、概要设计

又称为系统总体结构设计,系统开发过程中关键的一步。主要任务是将系统的功能需求分配给软件模块,确定每个模块的功能和调用关系,形成软件的模块结构图,即系统结构图。

三、详细设计

在概要设计中,将系统开发的总任务分解成许多基本的、具体的任务,为每个具体任务选择适当的技术手段和处理方法的过程称为详细设计。根据任务的不同,详细设计又可细分为:

1、网络设计
1)根据系统的要求选择网络结构,按照系统结构的划分,安排网络和设备的分布
2)根据物理位置考虑网络布线和设备的部署
3)根据实际的要求划定个网络节点的权限、级别和管理方式等
4)选择相应的系统软件和管理软件

2、代码设计
这里说的代码,不是指程序代码,而是指类似订单号这类的编号。特别提出来,作为一个设计种类,是希望确保代码(编号、编码)的唯一性、规范化和系统化。

3、输入输出设计
1)输入设计
目的确保向系统输入的数据的完整性、正确性和一致性,主要内容包括:
(1)确定输入数据的内容
(2)输入方式设计
(3)输入格式设计
(4)检验方式设计

遵循原则
(1)输入数据最少原则
(2)简单性原则。输入过程应尽量简单,既方便用户输入,节省时间,又可降低出错概率
(3)尽早验证原则。
(4)少转换原则。输入数据尽量采用原始的数据格式。

2)输出设计
目的确保输出数据的完整性、正确性和一致性,主要内容包括:
(1)确定输出的内容
(2)选择输出设备与介质
(3)确定输出格式

4、处理流程设计
不言而喻,懂的都懂。
内部执行过程,控制流,数据流。。。之类。

5、数据存储设计
选择数据存储的方式、存储介质、数据组织方式和记录格式,并估算数据的容量。主要包括:
(1)数据的统筹安排
看文件有多少,如何分布,数据是否共享,数据项存放于哪些文件。(不大好理解。)

(2)数据结构设计
其实就是数据库设计。

6、用户界面设计
黄金三原则:
1)置于用户控制之下
人机交互,允许交互的中断和撤销;允许用户定制交互方式。总之以用户为中心,用户最大。

2)减轻用户记忆负担
(1)符合用户直觉,直观
(2)快捷方式
(3)与真实世界保持一致
(4)傻瓜式操作
(5)提示及说明简洁易懂、用词准确,避免模棱两可

3)保持界面一致性

7、安全性和可靠性设计
对系统的运行环境和数据处理进行有效的控制,保证系统安全、有效地运行。

四、相关技术

(一)流程设计工具
在处理流程设计过程中,为了更清晰地表达过程规则说明,陆续出现了一些用于表示处理流程的工具,这些工具包括三类:
1)图形工具
程序流程图、IPO图、盒图、问题分析图、判定树

2)表格工具
判定表

3)语言工具
过程设计语言

1、程序流程图
Program Flow Diagram,PFD。无须多言。

2、IPO图
用IPO图对模块进行表述,用于描述每个模块的输入、输出和数据加工。

IPO图是系统设计中重要的文档资料之一,主体是处理过程说明,这个说明可以用流程图、判定树、判定表、盒图、问题分析图或过程描述语言来进行描述。IPO图中的输入、输出与功能模块、文件及系统外部项则需要通过数据字典来描述,并适当添加注释。

系统设计(还需要输入1个字)_系统设计


3、N-S图(盒图)

也是一种流程图,其创作出发点是为了避免流程图在描述程序逻辑时的随意性和灵活性。由顺序、选择等5种控制结构相互组合与嵌套而成。N-S图过程作用域明确,没有箭头,不能随意转移控制,而且容易表示嵌套关系和层次关系,具有强烈的结构化特征。但是问题很复杂时,N-S图可能很大。N、S是两个作者的名字首字母。也称为盒图。

系统设计(还需要输入1个字)_概要设计_02


4、问题分析图

Problem Analysis Diagram,PAD,也是一种流程图,描述详细设计的工具。由日立公司提出。PAD具有清晰的逻辑结构、标准化的图形等优点。更重要的是,它可以引导设计人员使用结构化程序设计方法,提高程序质量。

系统设计(还需要输入1个字)_系统设计_03


5、判定树

判定树(Decision Tree)也是用来表示逻辑判断问题的一种常用图形工具。用树来表达不同条件下的不同处理流程,比语言、表格都要直观。

系统设计(还需要输入1个字)_OOD_04


6、判定表

Decision Table。表格比语言描述较为直观

系统设计(还需要输入1个字)_概要设计_05


7、过程设计语言

Process Design Language,PDL。也称为结构化语言或伪代码(pseudo code)。

系统设计(还需要输入1个字)_OOD_06


(二)结构化设计和面向对象设计

系统设计可以分为结构化设计和面向对象设计两种方法。

结构化设计(Structured Design,SD)是一种面向数据流的方法,以需求规格说明书、系统分析阶段产生的数据流图和数据字典等文档为基础,是一个自顶向下、逐步求精和模块化的过程。

SD的基本思想是将软件设计成由相对独立且具有单一功能的模块组成的结构,分为概要设计和详细设计两个阶段,其中概要设计确定软件系统的结构,对系统进行模块划分,确定每个模块的功能、接口和模块之间的调用关系;详细设计负责为每个模块设计实现的细节。

面向对象设计方法里,并没有强调结构化方法那样的阶段性,因此一般不引入概要、详细设计的概念。如果非要有这种分工的话,可以将包的划分、类及对象间的关系、类的对外属性、方法及协作设计看做概要设计;类属性、方法的内部实现看做详细设计。

1、结构化设计
在结构化设计体系里,模块是系统的基本组成单位。模块的特点是可以自由组合、分解和变换,系统中任何一个处理功能都可以看成一个模块。

【模块原则】
1)信息隐蔽与抽象
采用封装技术,隐藏细节,使模块间的接口尽量简单,利于提高模块的独立性。这跟面向对象设计中的最少知识原则(迪米特法则,不跟陌生人讲话)是相通的。

2)模块划分要注意
(1)大小要适中
每个模块应该功能单一。过大则系统分解不充分,模块复杂度大,逻辑不清;多小则模块间调用频繁,依赖严重,模块反而失去独立性。

(2)多扇入,少扇出
多扇入,即被外部调用机会多,说明模块复用性很好;少扇出,依赖下级模块数量不能太多,降低复杂度。

(3)深度和宽度适中
深度表示模块的层数,宽度则是同一个层次上的模块总数的最大值。
层数过多,是否模块过小,适当合并;宽度过大,系统太复杂。宽度和深度应适当权衡。

3)低耦合

耦合指模块间的联系程度。

低耦合使得模块间尽可能相对独立,各模块可以单独开发和维护。

系统设计(还需要输入1个字)_系统设计_07


【内容耦合】

如果发生下列情形,两个模块之间就发生了内容耦合。

一个模块直接访问另一个模块的内部数据;

一个模块不通过正常入口转到另一模块内部;

两个模块有一部分程序代码重叠(只可能出现在汇编语言中);

一个模块有多个入口。

【公共耦合】
若一组模块都访问同一个公共数据环境,则它们之间的耦合就称为公共耦合。公共的数据环境可以是全局数据结构、共享的通信区、内存的公共覆盖区等。

【外部耦合】
一组模块都访问同一全局简单变量而不是同一全局数据结构,而且不是通过参数表传递该全局变量的信息,则称之为外部耦合。

【控制耦合】
如果一个模块通过传送开关、标志、名字等控制信息,明显地控制选择另一模块的功能,就是控制耦合。

【印记耦合】
如果一组模块通过参数表传递记录信息,就是标记耦合。它是某一数据结构的子结构(如结构体、对象等),而不是简单变量。

【数据耦合】
如果一个模块访问另一个模块时,彼此之间是通过数据参数(不是控制参数、公共数据结构或外部变量)来交换输入、输出信息的,则称这种耦合为数据耦合。

【非直接耦合】
消息耦合。
如果两个模块之间没有直接关系,它们之间的联系完全是通过主模块的控制和调用来实现的,这就是非直接耦合。这种耦合的模块独立性最强。

4)高内聚

内聚表示模块内部各成分之间的联系程度。是从功能角度来衡量模块内的联系。

内聚高使得模块的可理解性和维护性大大加强。

系统设计(还需要输入1个字)_架构设计_08


偶然内聚或巧合内聚:指一个模块内的各处理元素之间没有任何联系。

逻辑内聚:指模块内执行若干个逻辑上相似的功能,通过参数确定该模块完成哪一个功能。

时间内聚:把需要同时执行的动作组合在一起形成的模块。

过程内聚:指一个模块完成多个任务,这些任务必须按指定的过程执行。

通信内聚:指模块内的所有处理元素都在同一数据结构上操作,或者各处理使用相同的输入数据或产生相同的输出数据。

顺序内聚:指一个模块中的各个处理元素都密切相关于同一各功能且必须顺序执行,前一个功能元素的输出就是下一个功能的输入。

功能内聚:指模块内的所有元素共同作用完成一个功能,缺一不可。

【模块类型】
从上级模块(调用者)的角度来看,模块可分为以下类型:
1)传入模块
从下属模块获取数据,处理后传给上级模块。

2)传出模块
从上级模块获取数据,处理后传给下属模块。

3)变换模块
加工模块。从上级模块获取数据,处理后再传回上级模块。

4)协调模块
对所有下属模块进行协调和管理的模块。

2、面向对象设计
OOD是OOA的延续。基本思想是抽象、封装和可扩展性,其中可扩展性通过继承和多态来实现。

1)类
正如结构化设计体系里,模块是系统基本组成单位一样,在面向对象设计里,类是重要组成部分。它是具有相同属性、方法和关系的对象集合的总称。设计类是OOD中最重要的工作,也最为复杂和耗时。

类分为
(1)实体类
实体类映射需求中的每个实体,保存需要持久化的信息。实体类一定有属性,但不一定有方法。

(2)控制类
控制用例工作的类,一般是由动宾结构的短语(动词 + 名词 或 名词 + 动词)进行命名。通常,控制类可以没有属性,但一定有方法。

(3)边界类
边界类用于封装在用例内、外流动的信息或数据流。边界类使参与者能与系统交互,是一种用于对系统外部环境与内部运作之间的交互建模的类。每个参与者和用例交互至少要有一个边界类。通常,边界类既有属性也有方法。

常见的边界类有窗口、通信协议、打印机接口、传感器和终端等,甚至包括产生的报表。

(4)如何寻找和确定边界类
举个例子说明以上几个类的应用:在我们常用的网上交易系统中,用户和商品都可以作为实体类;而结算、发货等可作为控制类;商品页面、购物车则可作为边界类。

控制类特征比较明显,比较容易混淆的是实体类和边界类,或者说,比较难确定的是边界类。边界类和实体类一样,都是名词。如何寻找和定义边界类?可以检查用例模型,系统的每个参与者与用例的交互处至少有一个边界类。边界类将系统与其外部环境的变更分隔开,使这些变更不会对系统其他部分造成影响。边界类对系统中依赖于环境的部分进行建模,而实体类和控制类对独立于系统外部环境的部分进行建模。

边界类有个很明显的特征,就是与系统参与者(例如用户或外部服务)交互。充当系统内部和外部对话的中介和桥梁。系统参与者通过边界类使用系统,而边界类调⽤控制类对象进⾏相关的操作。如商品页面、购物车、图书借书(读者)证、图书过期罚金。

为啥借书证和罚金是边界类?它们都是名词,看上去,好像说是实体类也未尝不可。我猜,它们在图书系统中,作为一个类,在运行过程中,都需要读者的参与。出示借书证,缴纳罚款,都是读者的主动行为,在图书系统里面,借书证和罚金这两个类,除了属性,还有方法,这些方法调用了控制类,如检查有效性,计算罚金等。

一个系统可能会有多种边界类:
· 用户界面类 - 帮助与系统用户进行通信的类
· 系统接口类 - 帮助与其他系统进行通信的类
· 设备接口类 - 为用来监测外部事件的设备(如传感器)提供接口的类

2)系统分析阶段的类图和系统设计阶段的类图有何区别

在软件开发的不同阶段都使用类图,但这些类图表示了不同层次的抽象。在需求分析阶段,类图是研究领域的概念;在设计阶段,类图重点描述类与类之间的接口。

由于【分析类图】主要描述应用领域中的概念,它们的类可以从这些概念中得出,或者说分析类图中的类是从需求中获取的。

【设计类图】描述软件的接口部分,而不是软件的实现部分。设计类图使开发者之间更易于相互理解和交流。设计类图通常是在分析类图的基础上进行细化和改进的。

3)面向对象设计原则
六大原则
(1)开闭原则
对扩展开放,对修改关闭,即尽量在不修改原有代码的情况下进行扩展。

在OOD中,开闭原则一般通过在原有模块中添加抽象层(如接口或抽象类)来实现,这也是OOD其他原则的基础;其他原则可以说是开闭原则的具体措施。

(2)里氏替换原则
子类可以替换它的基类,反过来却不一定成立。尽量使用基类编程(编码时,使用基类;程序运行时,将具体子类替换基类对象)。

(3)依赖倒置原则
抽象不应该依赖于细节,细节应当依赖于抽象。即面向接口编程,而不是针对实现编程。

意思是,编码时,用接口或抽象类来进行变量、参数、返回值的类型声明,或者数据转换,而不要用具体类。同时为了确保这个原则,具体类应当只实现接口或抽象类中声明过的方法,不要给出多余的方法,否则无法调用这些新方法。

实现开闭原则的关键是抽象化,并且从抽象化导出具体化实现。如果说开闭原则是OOD的目标的话,依赖倒置就是OOD的主要机制。

(4)组合/聚合原则
又称为合成复用原则。尽量使用组合/聚合关系,少用继承。

在OOD中,可以通过组合/聚合或继承来复用已有的设计和实现,但首先应该考虑使用组合/聚合。原因是:

继承复用会破坏系统的封装性,因为基类的实现细节暴露给子类,称为白盒复用;
如果基类发生改变,子类也会受到影响;
子类从基类继承来的实现是静态的,无法在运行时改变,没有足够的灵活性;
继承只能在有限的环境中使用,例如,如果类没有声明不能被继承。

而组合/聚合关系关系可以将已有对象纳入到新对象中,成为新对象的一部分,按需调用,成员实现细节对新对象是不可见的,具有良好的封装性,称为黑盒复用;
相对继承,组合/聚合耦合度更低,成员对象的变化对新对象影响不大;
组合/聚合可以在运行时动态进行。

一般而言,两个类之间是Is-A,可使用继承;如果是Has-A,则应该使用组合/聚合。

(5)接口隔离原则
使用多个专门的接口,而不是一个单一的总接口,即接口单一职责,最小化原则。

(6)最少知识原则(迪米特法则)
是指一个软件实体应当尽可能少地与其他实体发生相互作用,当一个模块修改时,可以尽量少地影响其他模块。

信息隐藏,提高类独立性,降低类之间耦合度,利于子系统间的解耦。

将最少知识原则运用到系统设计中时,要注意几点:
类的划分上,应当尽量创建松散耦合的类,类之间的耦合度越低,越有利于复用;
类结构设计上,每个类都应当降低其属性和方法的访问权限;
在类的设计上,只要有可能,应当设计成不变类;
对其他类的引用上,一个对象对其他对象的引用应当降到最低。

(三)设计模式
分为创建型、结构型、行为型。

【创建型】
主要用于创建对象。

工厂方法、抽象工厂、原型、单例、建造者

【结构型】
主要用于处理类或者对象的组合

适配器、桥接、组合、装饰、外观、享元、代理

【行为型】
主要用于描述类或对象的交互以及职责的分配。

职责链、命令、解释器、迭代器、中介者、备忘录、观察者、状态、策略、模板方法、访问者