在完成前置的总体设计报告后,就应该开始着手于详细设计了,在这一步骤中,我们将需要去细化总体设计中提出的模块,详细的设计出每个模块的作用、算法,各个模块间的结构关系,通过需求分析中的结果,利用总体设计提出的大致框架设计出满足客户需求的软件系统产品。

一、   为什么需要详细设计

在总体设计完成后,应当对系统的整体有了大概的一个了解,但在没有对各个模块提出更为详细的要求的情况下,程序员难以对系统拥有准确的判断,从而导致系统运行效率低下,结构不清晰等等的问题,而在详细设置中,将会提出对每一个模块的性能要求、流程要求、用户界面要求等一系列详细的要求,这将会令编码者在编码实现的过程中思路更为清晰,减少编程过程中因合作产生的混乱,提高整个程序的开发效率。

二、   程序的结构化设计

“模块化设计是指在进行程序设计时将一个大程序按照功能划分为若干个小程序模块,每个小程序模块完成一个确定的功能,并在这些模块间建立必要的联系,通过模块的互相协作完成整个功能的程序设计方法。”[1]

在我们刚开始学习c语言程序设计时,我们通常习惯将所有的代码按照自己的思路写在同一个.c文件当中,虽然程序可以实现相应的功能,并且作者只需要标注良好的注释,就能在回看代码时重新理解代码的含义。但当程序需要分享或者工程量过于庞大需要多人协作完成一项程序时,这种面向过程编程的方式将是极其没有效率的,就如同在运动会上的接力赛跑,唯有当一个人完成了指定的任务和功能后,后面的成员才能开始其负责部分的代码,所以这种编程方法并不适用于大项目。

而程序的结构化设计很好的弥补了面向过程编程难以多人协作的问题,它将一个大程序拆分成一个一个小零件,每一个零件都有其自身的功能,并且零件便于程序测试,在每完成一个零件后可单独对其进行各种测试保证程序的运行正确无误,在完成所有的零件后,由一根主轴将所有的零件穿起来,利用零件的相互转换作为参数和返回值实现不同的程序功能。

同时模块化设计实现的程序也便于后期程序的维护,就如同一辆汽车,某个部件出现损坏或过时了,只需更换对应的部件即可,而模块化程序在出现错误时也只需对相应的部分进行修改更新,而在程序需要添加功能时,也只需要再制造所需要的零件进行组装即可。极大的降低了程序的维护更新成本。

模块化设计应当遵循以下原则:

  1. 模块之间相互独立。

每个模块要能独立的完成指定的工作,要保证模块尽可能少的和其他模块相关联,若模块间的联系过于紧密,将导致程序的结构化不够彻底,使得升级维护的成本提高。

  1. 模块大小要适当。

一个模块的大小不易太大,模块不可能将所有的程序功能都囊括进去,这样在不仅增加了实现难度的同时还使程序成为一个变相的面向过程,但也不适宜太小,否则就如同c语言中独立为一个函数就好。

  1. 模块的分解要有层次。

在模块的设计初期,首先设计范围比较大的模块,到后期再慢慢对大模块进行细化分解成较小的模块进行实现。

三、   人机界面设计

人机界面设计,又称人机互动(human-machine interaction),是专门研究系统与用户之间交互关系的学问。系统可以是各种机器,不过在本文,将会着重介绍人与计算机软件系统间的交互关系。

(一)    交互模式

好的界面应该是能够有效地让互动顺利进行,让使用者可以在已存在的应用范围中顺利轻松地完成他们的目的。

由Norman在1988年提出的人机对话的七个行为阶段,分别是:

  1. 形成目标。
  2. 形成意图。
  3. 指定动作。
  4. 执行动作。
  5. 领会系统状态。
  6. 解释系统状态。
  7. 评价结果。

Norman模型考虑系统为界面,只关心了系统表现和使用者期待之间的差距,并没有考虑系统透过界面产生的沟通。

后来由Abowd和Beale提出,延伸了Norman的模式,解决了Norman模式中的问题。除了使用者的任务语言(task-language)和界面的核语言(core-language)之外,还有代表输出和输入的语言,它们有时分开有时重叠。在互动中,四个主要的转换是:发出指示(articulation)、表现(performance)、呈现(presentation)、观察(observation)。

(二)    概念模型

“设计者或其他相关工程人员,所共同设计的操作接口称为概念模型。用户并无法直接与设计者进行对话,也鲜少透过说明书准确而有效地了解设计者的概念;透过与接口的交互,进而对该设计产品的功能及操作所形成的了解,则称为用户对于该产品所形成的心智模型。一般而言,用户的心智模型是在使用中自然逐步形成的,同时,借由与系统不断地交互,用户会不断修正其心智模型。如果到了最后,用户的心智模型与设计师的概念模型能一致或相当接近,那么,接口设计就算是相当成功了。”[2]

概念模型大致可分为依据活动所设计或依据对象所设计的两种导向。

活动型概念模型:

指令型——根据用户输入指令执行对应的操作,如Dos系统。

对话型——系统与用户进行对话,双向交互,但容易产生误解,如Siri语音助手。

操作导航型——让用户用最自然的直觉去操作接口,如MacOS、Windows系统等图形化系统。

搜索浏览型——用户通过关键词搜索信息,如百度搜索引擎。

对象型概念模型:

面向对象的概念模型将重点放在处于某些特定背景情境下使用的特定对象,它往往与其在现实生活中的原型极为类似,如机场中自助取票机等终端系统。

四、   详细设计所使用的工具及其使用方法

在详细设计中所使用到的工具大致分为三种:图形工具、表格工具以及语言工具。

(一)    程序流程图

在这几种工具中使用最为广泛的就是程序流程图了。它是表示算法、工程流的一种框图表示,以不同类型的框代表不同种类的步骤,在每个步骤之间则以箭头相连。在流程图的绘制前,需要先将任务流程梳理一边,并把需要执行的任务逐一写下,在绘制中,要遵守标准惯用的流程图符号,绘制的方向需符合从上到下,从左到右,文字说明需简洁扼要。在绘制完成后,还需要检查流程是否有所遗漏,或是有哪些流程需要调整。

流程图中常见的符号:[3]

 

软件开发设计完整的技术架构图 软件开发详细设计_详细设计

流程符号

用来表达过程的次序,用一条线由一个符号连接至另一个符号。如果不是标准的上至下、左至右图就会加上箭头。

 

软件开发设计完整的技术架构图 软件开发详细设计_软件开发设计完整的技术架构图_02

起止符号

表示次要或程序的开始和完结。通常会在其中表上“开始”或“结束”或其他相关字眼。

 

软件开发设计完整的技术架构图 软件开发详细设计_伪代码_03

程序

以长方形来表示一系列程序去改变量值、形式、数据的位置。

 

软件开发设计完整的技术架构图 软件开发详细设计_软件开发设计完整的技术架构图_04

判断

以菱形去表示一个条件进程,用来按情况去决定下一步的走向。通常以True或False的值来决定。

 

软件开发设计完整的技术架构图 软件开发详细设计_详细设计_05

输入/输出

以平行四边形来标示数据输入或输出的过程,即填入数据或显示工作结果的步骤。

 

软件开发设计完整的技术架构图 软件开发详细设计_伪代码_06

注解

用来补充某步骤的额外信息,可用一个虚线来连接一个半闭合的长方型至想注释的符号中。

 

软件开发设计完整的技术架构图 软件开发详细设计_伪代码_07

已定义流程

用一个有2条左右垂直线长方型,来表示一个已在其他地方定义了的过程。

 

软件开发设计完整的技术架构图 软件开发详细设计_详细设计_08

同页参考

用一个含有字母的小圆圈来连接目标流程画于同一页上。

 

软件开发设计完整的技术架构图 软件开发详细设计_概念模型_09

换页参考

用一个倒画的屋型来表示目标流程画于另一页上。

 

(二)    伪代码

另一种常用来表示程序流程、描述算法的一种方法就是伪代码。它是属于语言工具的一种,虽然名称中包含代码二字,但实际上不是一种现实存在的编程语言,可能会综合使用多种编程语言的语法、保留字,甚至会用到英文、中文等自然语言来说明流程。

当程序员需要实现一个具体的算法时,尤其是对于一个不熟悉的算法时,通常就会从伪代码开始对算法进行理解,然后将伪代码翻译为所需要的目标编程语言,并让翻译出来的程序与其余的程序相互匹配。

在详细设计的阶段,就可以使用伪代码对实际算法和程序结构进行充分描述说明,直到编码阶段再通过翻译伪代码的形式完成编码过程。

伪代码例子(C语言风格):

void function fizzbuzz {
  for (i = 1; i <= 100; i++) {
    set print_number to true;
    If i is divisible by 3 {
      print "Fizz";
      set print_number to false; }
    If i is divisible by 5 {
      print "Buzz";
      set print_number to false; }
    If print_number, print i;
    print a newline;
  }
}

(三)    判定表和判定树

判定表是一种间接的可视化表示,用于指定根据给定条件所相对应的操作。判定表相较于流程图和伪代码而言,可以更清晰的表示条件复杂情况下的分支选项。

判定表通常由四个部分组成:条件桩、动作桩、条件项、动作项。

条件桩用来列出问题的所有条件,动作桩用来规定在满足某些条件下可能采取的操作,条件项用来列出针对条件桩中各种情况的真假值的各种组合,动作项用于列出对应各种条件项所对应需要采取的动作。

判定表虽然能够清晰的表示复杂的条件组合与采取相应动作的对应关系,但是要看懂这么一个表还是需要学习成本的,所以,判定树就诞生了,它是判定表的变种,降低了学习成本,使其易于掌握和理解使用,但是相较于判定表,简洁性却有所降低,并且当数据元素越接近叶子时,需要重复书写的部分越多。判定树的功能和判定表相同,需要我们根据实际情况选择合适的使用。

下面是判定表的一个例子:[4]

 

1

2

3

4

5

6

7

8

9

国内乘客

 

T

T

T

T

F

F

F

F

头等舱

 

T

F

T

F

T

F

T

F

残疾乘客

 

F

F

T

T

F

F

T

T

行李重量W≤30

T

F

F

F

F

F

F

F

F

免费

×









(W-30)×2




×






(W-30)×3





×





(W-30)×4


×






×


(W-30)×6



×






×

(W-30)×8






×




(W-30)×12







×



下面是判定树的一个例子:[5]

 

软件开发设计完整的技术架构图 软件开发详细设计_详细设计_10

 

(四)    文学编程

文学编程,又名文字式编程,是高德纳提出的编程方法,并被期望能取代结构式编程的范型。“文学程序是用自然语言(比如英语)写出来的对程序逻辑的解释,程序中交织点缀着宏和传统源代码段。”[6]这是维基百科中对文学编程的解释。这种工具将代码段或更低层次的宏隐藏了起来,实际用法也与伪代码写的算法类似。

关于文学编程的优点,文学编程强迫程序员显式描述程序背后的思路,让不充分的设计决策无所遁形。同时,文学编程还提供了一流的文档系统,文档能使作者能在以后的任何时间重新找到自己的思路,也能使其他程序员更容易理解程序的建构过程。文学编程的元语言(meta-language)能力也据称普遍利于思考,能从更高的层次统观代码。

但是文学编程也有显著的缺点,通常而言,文学编程就是把代码撕裂成多个代码片段,然后再通过拼接构成一个软件,而拆分成过多的文件将导致代码阅读上的困难。相较于优点而言,这些缺点过于严重,所以在当前时期,已经很少有人采用文学编程作为常用工具了。

五、   详细设计小结

这个阶段的关键任务是确定怎样具体的实现用户需求的软件系统,在保证程序稳定可靠的同时在结构上要易于维护,也要易于程序员阅读理解、测试修改等。要保证上述的要求,结构化的程序设计是其基本保障。

在人机界面的设计上,要实现用户易于上手,保证界面的直观和较低的学习成本,同时保证程序的响应速度在合理的范围内,以提高用户的使用体验。

在进行详细设计的过程中,若仅仅使用文字性的描述,就会导致设计过于的抽象难懂,而使用一些图形工具或伪代码等工具,将使得设计的思想更为清晰易懂且不易产生误解,因此,要善于使用直观的工具进行设计。