第三讲 软件设计
大连海事大学计算机学院软件工程研究室 蒋 波
软件设计阶段要解决的问题是“How to do”的问题。就是说,需将整个系统划分出系统的物理组成元素(程序、文件、DB、人工过程、文档)。
软件设计分为基本设计和详细设计两个部分。基本设计的主要工作是确定系统的结构、进行模块化划分、确定每一个模块的功能、规定每一个模块的接口及调用关系、确定全局数据结构等;详细设计的主要工作是为每一个模块设计其实现细节并确定各个局部数据结构。
软件设计过程是:首先在需求描述的基础上设想实现目标系统的各种可能的方案,然后从这些可供选择的方案中选取若干个合理的方案,为每个合理的方案都准备一份系统流程图、列出组成系统的所有物理元素、分别进行成本/效益分析、制定实现这个方案的进度计划等。最后通过综合比较分析这些合理方案,从中选出一个最佳方案推荐给用户。如果用户接受了推荐的方案,分析员应该进一步为这个最佳方案设计软件结构。通常,设计出初步的软件结构后,还需要多方改进以便得到更合理的结构。在此基础上进行必要的数据库设计,确定测试要求并且制定测试计划。
总体设计的目的就是要站在全局高度,在较抽象的层次上分析对比多种可能的系统实现方案和软件结构,从中选出最佳方案和最合理的软件结构,从而用较低成本开发出较高质量的软件系统。通常由两个主要阶段组成:系统设计——确定系统的具体实现方案;结构设计——确定软件结构。
一. 基本设计(总体设计)
1. 软件设计过程(基本任务)
1) 依据需求分析的基础设想可供选择的方案;
依据DFD设计各种可能的处理组合——方案。在这个过程中,分析员依据各个处理边界逐个设想可供选择的方案,并不评价各种方案的优劣。
2) 选取合理的方案;
通常选取低成本、中成本、高成本的三种方案,根据可行性研究阶段所理解的用户的各种需求进行选择。对每一个合理的方案,准备系统流程图、组成系统的物理元素清单、成本和效益分析、实现系统的进度计划等。
成本估算的方法:代码行价格技术、任务分解技术、FP技术、自动估算技术(分别解释)。
3) 推荐最佳方案;
分析员应该综合分析对比各种合理方案的利弊,在合理的方案中找最佳方案并制定详细的执行计划。
4) 功能分解;
1.结构设计:确定组成各功能服务的模块以及模块与模块之间的关系。
2.过程设计:确定每个模块的内部处理过程。
通过分解系统的各个复杂功能,将系统的功能服务细化到很容易实现的地步。在面向数据流的设计方法中,这个过程采用细化数据流图的方法实施。
结构设计是总体设计阶段的任务,过程设计是详细设计阶段的任务。为确定软件结构,首先需要从实现角度把复杂的功能进一步分解。分析员结合算法描述仔细分析数据流图中的每个处理,如果一个处理的功能过分复杂,必须把它的功能适当地分解成一系列比较简单的功能。一般说来,经过分解之后应该使每个功能对大多数程序员而言都是明显易懂的。功能分解导致数据流图的进一步细化,同时还应该用IPO图或其地适当的工具简要描述细化后每个处理的算法。
5) 设计软件结构;
通常一个模块完成一个适当的子功能。用层次图或结构图来清楚地描述各功能模块之间的调用关系。(举例说明层次图或结构图的例子)。
如果数据流图已经细化到适当的层次,则可以直接从数据流图映射出软件结构,我们将以面向数据流的设计方法为例详细介绍该过程。
6) 设计数据库结构;
模式设计;子模式设计;完整性与安全性设计;优化。
7) 制定测试计划;
在软件开发的早期指定测试计划,能够促使设计人员在设计软件时充分注意提高软件的可测试性。
8) 书写文档;
完成下列文档的书写:
系统说明:包括系统流程图、系统构成方案、组成系统的物理元素清单、成本/效益分析;最佳方案的描述与细化的DFD;软件结构图;用IPO图或其他工具(例如,PDL语言)简要描述的各个模块的算法;模块间的接口关系以及需求、功能和模块三者之间的交叉参照关系等等。
用户手册:修改在系统分析阶段所形成的用户手册。
测试计划:包括测试策略、测试方案、预期的测试结果、测试的进度计划等。
详细实施计划:里程表,软件项目管理的进度管理工具。
数据库设计结果:包括数据库管理系统的选择、模式、子模式、完整性和安全性、以及优化方法,数据字典等。
9) 审查与复审:技术人员的技术审查与管理人员的复审。
2. 软件设计的概念和原理
1) 模块化:将复杂功能进行分解的过程。
模块是数据说明、可执行语句等程序对象的集合,它是单独命名且可通过名字来访问的。例如,过程、函数、子程序、宏等等都可作为模块。模块化就是把程序划分成若干个模块,每个模块完成某个子功能的过程。把这些模块集总起来组成一个整体,可以完成指定的功能满足问题的要求。
设函数C(x)定义问题x的复杂程度,函数E(x)确定解决问题x需要的工作量(时间)。对于两个问题P1和P2,如果
C(P1)> C(P2)
显然,E(P1)> E(P2)
根据人类解决一般问题的经验,另一个有趣的规律是
C(P1 + P2) > C(P1)+ C(P2)
也就是说,如果一个问题由P1和P2两个问题组合而成,那么它的复杂程序大于分别考虑每
个问题时的复杂程度之和。
综上所述,得到下面的不等式
E(P1 + P2)> E( P1)+ E( P2)
但是,如果这样无限制地分割下去,是不是意味着开发软件所需的工作量也就小得可以忽略了呢。事实上,当模块数目增加时每个模块的规模将减小,开发单个模块需要的成本(工作量)确实减少了,但是随着模块数目增加,设计模块间接口所需要的工作量也将增加。
2) 抽象
在模块化求解问题时,可以得到许多抽象的层次。在抽象的最高层次使用问题环境的语言,以概括的方式叙述问题的解法;在较低抽象层次采用更过程化的方法,把面向问题的术语和面向实现的术语结合起来叙述问题的解法;最后,在最低的抽象层次用可以直接实现的方式叙述问题的解法。
软件工程过程的每一步都是对软件解法的抽象层次的一次精化。在可行性研究阶段,软件作为系统的一个完整部件;在需求分析期间,软件解法是使用在问题环境内熟悉的方式描述的;当我们由总体设计向详细设计过渡时,抽象的程度也就随之减少了;最后,当源程序写出来以后也就达到了抽象的最低层。
逐步求精和模块化的前提是抽象。从事物的本质出发暂时忽略一些细微的差异。这也是设计重用软件的基础
3) 信息隐蔽和局部化
将与模块相关联属性局限在模块的内部,尽量减少模块间的联系。
信息隐蔽原理指出:应该这样设计和确定模块,使得一个模块内包含的信息(过程和数据)对于不需要这些信息的模块来说,是不能访问的。
模块独立的概念是模块化、抽象、信息隐蔽和局部化概念的直接结果。
开发具有独立功能而且和其他模块之间没有过多的相互作用的模块,就可以做到模块独立。换句话说,希望这样设计软件结构,使得每个模块完成一个相对独立的特定子功能,并且和其他模块之间的关系很简单。
为什么模块的独立性很重要呢?主要有两条理由:第一有效的模块化(即具有独立的模块)的软件比较容易开发出来。这是由于能够分割功能而且接口可以简化,当许多人分工合作开发同一个软件时,这个优点尤其重要。第二,独立的模块比较容易测试和维护。这是因为相对说来,修改设计和程序需要的工作量比较小,错误传播范围小,需要扩充功能时能够“插入”模块。总之,模块独立是好设计的关键,而设计只是决定软件质量的关键环节。
模块的独立程度可以由两个定性标准度量,这两个标准分别称为内聚和耦合。耦合衡量不同模块彼此间互相依赖(连接)的紧密程度;内聚衡量一个模块内部各个元素彼此结合的紧密程度。以下分别详细阐述。
4) 模块独立及其度量
耦合 衡量不同模块彼此相互依赖的紧密程度的一种度量
内聚 衡量模块内部各个元素彼此结合的紧密程度的一种度量
耦合方式:(7种)每种耦合尽量举例说明。
非直接耦合 两个模块没有直接的联系,互相都不依赖于对方而能独立地工作; 数据耦合 两个模块借助于参数表传递简单数据;
标记耦合 两个模块借助于参数表传递数据结构的一部分;
控制耦合 两个模块间传递的信息中包含有用于控制模块内部逻辑的控制信息; 外部耦合 模块与软件以外的环境有关;
公共耦合 多个模块引用同一全局数据区的模式;
内容耦合 两个模块间出现了下列情况之一:
a) 一个模块访问另一个模块的内部数据;
b) 一个模块不通过正常的入口转到另一个模块的内部;
c) 两个模块有一部分程序代码重叠(汇编语言程序)
d) 一个模块有多个入口
自上而下,其耦合程度越来越强。
内聚方式:(7种):每种内聚尽量举例说明。
偶然内聚 一个模块完成一组任务,这组任务彼此间即使有关系,其关系也是松散
的;
逻辑内聚 一个模块完成逻辑上相关的一组任务;
瞬时内聚 一个模块所包含的任务必须在同一时间间隔内执行(如初始化模块); 过程内聚 一个模块的处理元素是相关的,而且必须按特定的次序执行;
通信内聚 一个模块的所处理元素集中在一个数据结构的区域上(如所有处理元素
使用同一输入数据);
顺序内聚 一个模块的处理元素是相关的且必须顺序执行;
功能内聚 一个模块完成一个单一的功能,模块中的各部分在此目标下协同工作且
都是完成这一功能不可缺少的;
自上而下,其内聚程度越来越强。
3. 软件设计的原则
1) 满足信息隐蔽原则;
2) 尽量做到高内聚、低耦合;
3) 模块的大小适中,以完成一个相对独立的功能为宜;
4) 模块的调用深度不宜过大;
5) 模块的扇入应尽量大,而扇出不宜过大;
6) 设计单入口和单出口的模块;
7) 模块的作用域应在控制域之内;
模块的作用域定义为受该模块内一个判定影响的所有模块的集合。
模块的控制域定义为该模块本身及直接或间接从属于该模块的模块集合。
模块M的作用域为{A,B,C,D,E,F}
模块M的控制域为{M,A,B,C,D,E,F}
在一个设计得很好的系统中,所有受判定影响的模块应该都从属于做出判定的那个模块,最好局限于做出判定的那个模块本身及它的直属下级模块。例如,图中模块A做出的判定只影响模块B,那么是符合这条规则的。但是,如果模块A做出的判定同时还影响模块G中的处理过程,那就不满足这个原理了。这样做的坏处是:首先,这样的结构使得软件难于理解。其次,为了使得A中的判定能影响G中的处理过程,通常需要在A中给一个标记用以记录判定的结果,并将这个标记传递给A和G的公共上级模块M,再由M把它传给G。这个标记是控制信息而不是数据,因此将使模块间出现控制耦合。
怎样修改软件结构才能使作用域是控制域的子集呢?一个方法是把做判定操作上移,例如,把判定从模块A中移到模块M中。另一个方法是把那些在作用域中但不在控制域内的模块移到控制域内,例如,把模块G移到模块A的下面,成为它的直属下级模块。
到底采用哪种方法改进软件结构,需要根据具体问题统筹考虑。一方面应该考虑哪种方法更现实,另一方面应该使软件结构能最好地体现问题原来的结构。
8) 模块的功能应该是可以预测的。
功能可预测是指对于相同的输入,应该得到相同的输出。
4. 图形工具(参见邓书P40-45)
1) 层次图和HIPO图
2) 结构图
5. 面向数据流的设计方法(结构化程序设计方法)
结构化设计方法SD是一种面向数据流的设计方法。它与结构化分析SA相衔接。SD采用结构图(Structure Chart-SC)来描述程序结构。
5.1 步骤:(参见流程图部分)
1)复查并精化DFD;
2)确定DFD的信息流类型(变换流或事务流);
3)根据数据流类型分别实施变换分析或事务分析;
4)根据软件设计原则对程序结构图作优化。
下图说明了面向数据流设计方法的过程
在一个设计得很好的系统中,所有受判定影响的模块应该都从属于做出判定的那个模块,最好局限于做出判定的那个模块本身及它的直属下级模块。例如,图中模块A做出的判定只影响模块B,那么是符合这条规则的。但是,如果模块A做出的判定同时还影响模块G中的处理过程,那就不满足这个原理了。这样做的坏处是:首先,这样的结构使得软件难于理解。其次,为了使得A中的判定能影响G中的处理过程,通常需要在A中给一个标记用以记录判定的结果,并将这个标记传递给A和G的公共上级模块M,再由M把它传给G。这个标记是控制信息而不是数据,因此将使模块间出现控制耦合。
怎样修改软件结构才能使作用域是控制域的子集呢?一个方法是把做判定操作上移,例如,把判定从模块A中移到模块M中。另一个方法是把那些在作用域中但不在控制域内的模块移到控制域内,例如,把模块G移到模块A的下面,成为它的直属下级模块。
到底采用哪种方法改进软件结构,需要根据具体问题统筹考虑。一方面应该考虑哪种方法更现实,另一方面应该使软件结构能最好地体现问题原来的结构。
8) 模块的功能应该是可以预测的。
功能可预测是指对于相同的输入,应该得到相同的输出。
4. 图形工具(参见邓书P40-45)
1) 层次图和HIPO图
2) 结构图
5. 面向数据流的设计方法(结构化程序设计方法)
结构化设计方法SD是一种面向数据流的设计方法。它与结构化分析SA相衔接。SD采用结构图(Structure Chart-SC)来描述程序结构。
5.1 步骤:(参见流程图部分)
1)复查并精化DFD;
2)确定DFD的信息流类型(变换流或事务流);
3)根据数据流类型分别实施变换分析或事务分析;
4)根据软件设计原则对程序结构图作优化。
下图说明了面向数据流设计方法的过程
5.2 例子
1)变换分析
确定输入流和输出流,孤立出变换中心;
第一级分解;
第二级分解。
2)事务分析
确定事务中心和每条活动流信息;
将事务流型DFD映射成高层的程序结构;
进一步分解。
二. 详细设计
1. 结构化程序设计
1) 顺序结构;
2) 分支结构;
3) 循环结构;
4) GOTO语句的讨论
2. 详细设计工具
1) 程序流程图
2) 盒图(N-S图)
3) PAD图
4) 判定表 (参见邓书P45)
5) 判定树 (参见邓书P45)
6) 过程设计语言PDL(Process Design Language)
3. 详细设计说明书
1) 概要功能说明;
2) 画面格式设计与说明;
3) 数据关联图;
4) 输入/输出数据项的详细描述;
5) 处理功能逻辑说明(流程图等);
6) 画面迁移(功能逻辑关系的反映)。
4.详细设计说明书例子(参见附加资料)
三、Jackson方法
下面介绍一种面向数据结构的软件开发方法,它包括Jackson于20世纪70年代提出的JSP(Jackson Structured Programming)和80年代提出的JSD(Jackson System Development)。
早期的Jackson方法用于开发规模较小的数据处理系统的设计,80年代后期,Jackson在JSP的基础上扩展成了一种系统的开发方法,即JSD。JSD主要以活动事件为中心,通过由一串活动顺序组合构成的进程,建立系统模型,最后实现该模型。
一 概述
1. 产生
JSP方法是一种面向数据结构,以数据驱动的程序设计方法。它是20世纪70年代由M.Jackson提出的。该方法在设计较简单的数据处理系统时特别方便,当设计比较复杂的程序时常常遇到输入数据可能有错、条件不能预先测试和数据结构冲突等问题。为了克服这个困难,1978~1981年间Jackson与J.R.Cameron共同开发出了JSD方法,增加了一系列比较复杂的辅助技术,使之适合于大型系统的开发。它以事件为驱动,是基于进程模型的。
2. 基本思想
程序和数据的密切关系可追溯到计算技术的起源,把程序看成数据,把数据看成程序,在20世纪60年代,有一派人主张,内在数据结构是至关紧要的,可利用输入数据结构和输出数据结构来推导出程序结构。在许多领域中,存在着明显的层次信息结构,层次数据组织常常和使用这些数据的程序十分相似,数据的结构十分出色地指示了程序的结构。面向数据结构的设计方法就是利用这些结构作为开发软件的基础。
3. 设计和数据结构的关系
数据结构影响软件结构和过程,程序加工的是数据,程序表述的算法在很大程度上依赖于作为基础的数据结构。如记录、表及结构等类型的数据,分量与分量之间是一种顺序结构,程序处理必然是顺序的控制结构;数组、文件每个分量占据的空间一样大且连续存放,程序处理必然是循环的控制结构;变体记录、联合等类型的数据是一种选择覆盖的结构,程序处理必然是分支的控制结构;数据结构分层次(如文件由许多记录组成),程序结构也必然分层。因此,数据结构不但影响程序的结构,也影响着程序的处理过程。所以70年代中期出现了“面向数据结构”的设计方法,其中有代表性的是由M.Jackson提出的Jackson方法和由J.Warnier提出的Warnier方法。
4. SD方法和JSP方法的异同
面向数据流的设计(SD方法)和面向数据结构的设计(JSP方法)的共同点都是数据信息驱动的,都试图将数据表示转换成软件表示,不同之处在于面向数据结构的设计不利用数据流图,而根据数据结构的表示来设计。JSP方法定义了一组以数据结构为指导的映射过程,它根据输入、输出的数据结构,按一定的规则映射成软件的过程描述,最终目标是生成软件过程的描述,即程序结构,而不是软件的体系结构。而SD方法是根据数据流图来设计,最终目标是建立软件体系结构的描述,即软件模块的层次结构。
5. JSP方法的优缺点
JSP方法的优点:简单,适合于规模不大的系统,建立了问题的数据结构之后,可直接推导出相应的程序结构。
JSP方法的局限性:不适合于大系统,当输入数据结构与输出数据结构不相同且无对应关系时,难于应用。当数据结构发生变化时,程序结构也发生变化,一般是总体上用SD方法,局部范围用JSP方法。
二 JSP 方法
JSP是为中小型数据处理系统设计程序结构的一种方法,其设计原则是“程序结构同数据结构相对应”。JSP的描述工具有Jackson图和纲要逻辑,纲要逻辑是一种描述算法过程的语言,它分别用seq,iter和 sel-alt三类关键字描述顺序、重复和选择三种结构。
2.1 Jackson图
Jackson图是JSP方法的描述工具,在分析、确定问题的数据结构后,用Jackson图来描绘问题的数据结构。
1. Jackson图的表示
虽然程序中实际使用的数据结构种类繁多,但是它们的数据元素彼此间的逻辑关系却只有顺序、选择和重复三种,因此,逻辑数据结构也只有这三种。
1) 顺序结构
顺序结构的数据由一个或多个数据元素组成,每个元素按确定次序出现一次。如图9.1(a)中的A是一个顺序结构,指出基本成份B,C,D顺序组成。注意,这里的A并非模块,它既可以是数据(表示数据结构时),又可以是程序(表示程序结构时),而B,C,D仅是A的成份,上、下层是“组成”的关系,A中除了B,C,D外不包含其他代码,不同于Yourdon方法的软件结构。
2) 选择结构
选择结构的数据包含两个或多个数据元素,每次使用这个数据时按一定条件从这些数据元素中选择一个。如图9.1(b)中的A是一个选择结构,由数据元素 B,C或 D组成。
3) 重复结构
重复结构的数据,根据使用时的条件由一个数据元素出现零次或多次构成。如图9.l(c)所示,表示A由多个数据元素B组成。
(a)顺序结构; (b)选择结构; (c)重复结构
图 9.1 Jackson图
2. Jackson图的优点
Jackson图具有如下优点:
(1) 便于表示层次结构,是对结构进行自顶向下分解的有力工具。
(2) 形象直观可读性好。
(3) 既能表示数据结构也能表示程序结构(因为程序结构也只有上述三种基本类型)。
3. Jackson图应用的示例
某仓库管理系统每天要处理大批由单据所组成的事务文件。单据分为订货单和发货单两种,每张单据由多行组成,订货单每行包括零件号、零件名、单价及数量等4个数据项,发货单每行包括零件号、零件名及数量等3个数据项,用Jackson结构图表示该事务文件的数据结构。图9.2为该事务文件的数据结构。
图9.2 事务文件的Jackson结构图
2.2 纲要逻辑
纲要逻辑是类似于伪码的一种语言表示工具,与Jackson结构图对应,用于将Jackson结构图表示的程序结构转换为语言表示。
图9.l中对应的纲要逻辑为:
(1)顺序结构:
A seq
B
C
D
A end
(2) 选择结构:
A sel 条件 1
B
alt 条件2
C
alt 条件3
D
A end
(3) 重复结构:
A iter until(或while)条件
B
A end
2.3 开发步骤
JSP方法基本由下列5个步骤组成:
(1) 分析并确定输入数据和输出数据的逻辑结构,并用Jackson图描绘这些数据结构。
(2) 找出输入数据结构和输出数据结构中有对应关系的数据单元。所谓有对应关系是指有直接的因果关系,在程序中可以同时处理的数据单元(对于重复出现的数据单元必须是重复的次序和次数都相同才可能有对应关系)。
(3) 用下列3条规则从描绘数据结构的Jackson图导出描绘程序结构的Jackson图; ① 为每对有对应关系的数据单元,按照它们在数据结构图中的层次和在程序结构图的相应层次画一个处理框(如果这对数据单元在输入数据结构和输出数据结构中所处的层次不同,则和
它们对应的处理框在程序结构图中所处的层次与它们之中在数据结构图中层次低的那个对应)。
② 根据输入数据结构中剩余的每个数据单元所处的层次,在程序结构图的相应层次分别为它们画上对应的处理框。
③ 根据输出数据结构中剩余的每个数据单元所处的层次,在程序结构图的相应层次分别为它们画上对应的处理框。
(4) 列出所有操作和条件(包括选择条件和重复结束条件),并把它们分配到程序结构图的适当位置。
(5) 用纲要逻辑表示程序。
2.4 JSP方法应用示例
现举例说明JSP方法设计过程。
1) 问题陈述
某仓库存放多种零件(如 P1,P2,„„),每个零件的每次进货、发货都有一张卡片作出记录,每月根据这样一叠卡片打印一张月报表。报表每行列出某种零件本月库存量的净变化。用JSP方法对该问题进行设计。
2) 建立输入、输出数据结构
建立输入、输出数据结构的步骤如下:
(1) 输入数据:根据问题陈述,同一种零件的进货、发货状态不同,每月登记有若干张卡片。把同一种零件的卡片放在一起组成一组,所有的卡片组按零件名排序。所以输入数据是由许多零件组组成的文件,每个零件组有许多张卡片,每张卡片上记录着本零件进货或发货的信息。因此输入数据结构的Jackson图为图9.3(a)。
(2) 输出数据:根据问题陈述,输出数据是一张如图9.3*)的月报表,它由表头和表体两部分组成,表体中有许多行,一个零件的净变化占一行,其输出数据结构的Jackson图为图
9.3(b)。
3) 找出输入、输出数据结构中有对应关系的单元
月报表由输入文件产生,有直接的因果关系,因此顶层的数据单元是对应的。表体的每一行数据由输入文件的每一个“零件组”计算而来,行数与组数相同,且行的排列次序与组的排列次序一致,都按零件号排序。因此“零件组”与“行”两个单元对应,以下再无对应的单元。
图9.3 某仓库系统输入、输出数据结构
(a)输入数据结构;(b)输出数据结构;(c)输出表
4) 导出程序结构
找出对应关系后,根据以下规则导出程序结构:对于输入数据结构与输出数据结构中的数据单元,每对有对应关系的数据单元按照它们所在的层次,在程序结构图适当位置合画一个处理框,无对应关系的数据单元,各画一个处理框。
根据以上规则,画出的程序结构图如图9.4所示。
在图9.4的程序结构的第4层增加了一个“处理零件组”的框,因为改进的Jackson图规定顺序执行的处理中不允许混有重复执行和选择执行的处理。增加了这样一个框,使符合该规定,同时也提高了结构图的易读性。
图9.4 某仓库系统程序结构
5) 列出并分配操作与条件
为了对程序结构作补充,要列出求解问题的所有操作和条件,然后分配到程序结构图 的适当位置,就可得到完整的程序结构图。
(1)本问题的基本操作列出如下:
A、终止 B、打开文件 C、关闭文件 D、打印字符行 E、读一张卡 F、产生行结束符 G、累计进货量 H、累计发货量 I、计算净变化 J、置零件组开始标志
(2) 列出条件如下:
I(l):输入条件未结束 I(2):零件组未结束 S(3):进发货标志
将操作与条件分配到适当位置的程序结构图如图9.5所示。
图9.5 分配操作后的程序结构图
在分配操作时注意:为了能获得重复和选择的条件,Jackson建议至少超前读一个记录,以便使得程序不论在什么时候判定,总有数据已经读入,并做好使用准备。因此在图9.5中,将操作E(读一张卡)放在打开文件之后,同时在处理完一张卡片后再读一次。
6) 用纲要逻辑写出程序
Jackson方法中的纲要逻辑与Jackson所示的程序结构图完全对应,用纲要逻辑写出程序的过程,实际上就是自顶向下用这些纲要逻辑替换Jackson图中每个处理框的过程,每个处理框都看作是下层处理框及分配在上面的操作组成。
图9.5所示的程序结构的纲要逻辑为:
产生月报表 seq
打开文件
读一张卡
产生表头 seq
打印字符行
产生表头end
置零件组开始标志
产生表体 iter while输入文件未结束
由零件组产生输出行seq
处理零件组 iter while零件组未结束
处理卡片sel进货标志
处理进货seq
累计进货量
处理进货end
alt发货标志
处理发货seq
累计发货量
处理发货end
处理卡片end
读一张卡
处理零件组end
产生零件名seq
打印字符行
产生零件名end
产生净变化seq
计算净变化
打印字符行
产生净变化end
换行
置零件组开始标志
由零件组产生输出行end
产生表体end
关闭文件
终止
产生月报表end
用纲要逻辑书写程序可以很方便地转换成源代码,还可以检查前面步骤的错误。如果分配操作不正确或者结构图不正确,都难以写出它的纲要逻辑。
2.5 结构冲突问题
JSP方法适用于输入数据和输出数据结构之间有对应关系的问题求解。但有些情况下,输入数据和输出数据结构之间找不到对应关系,若仓库系统中的卡片不按零件名分组,而是按进货、发货的日期顺序排列,这样“零件组”与“行”就不对应了。输入数据与输出数据结构找不到对应关系的情况,称为结构冲突。对这种结构冲突的问题,Jackson提出了引入中间数据结构或中间文件的办法,将冲突部分分隔开来,建立多个程序结构,再利用中间文件把它们联系起来,构成一个系统的整体。
例如有一个卡片文件,存放一个矩阵,每张卡片包含矩阵的一行元素。要求按列打印该矩阵,即输出的每一行是矩阵的每一列元素。这个问题的输入数据与输出数据在结构上是冲突的,是次序冲突。解决的办法是构造两个程序结构,分别解决输入和输出的问题,在输入和输出之间增加一个分类程序,将输入产生的按行排列的矩阵转换成按列排列的矩阵,然后再输出。这个按列排列的矩阵即为中间数据结构或中间文件。
三、 JSD 方 法
3.1 JSD概述
1. JSD的产生
JSD方法是JSP的扩充,它是因JSP的缺陷而产生的。9.2节已经讲到JSP方法是基于输入数据结构和输出数据结构的对应复合而成程序结构的,但当要开发的系统十分庞大时,输入数据结构和输出数据结构之间就会出现大量复杂的、JSP难以对付的结构冲突问题,致使软件系统结构无法形成,因而它只是一种程序设计方法,只适用于小型程序的开发。
2. JSD的基本思想
1) 分而治之的原则
JSD则是采用“分而治之”的复杂性控制原则,将系统大量复杂的输入数据流和输出数据流分离为一些独立的、彼此无关联的、结构简单的输入数据流和一些独立的、彼此无关联的输出数据流,其中每一简单的输出数据流仅关联于少数几个简单的输入数据流。这样,一个错综复杂的庞大问题就转化为多个互不关联的独立的小型程序开发问题,这些小型程序在开发时不会出现复杂的结构冲突,即可直接使用JSP方法了。
2) 确定实体
对于系统输入数据流的分离,JSD方法追溯系统输入数据流的真正内含,即系统输入数据流是系统所关注的客观世界动态行为的一种信息表述。因此,JSD方法根据用户的专业知识,对客观世界行为进行自然划分,将系统输入数据流分离为多个彼此独立的输入数据流,其中每种独
立的输入数据流对应于客观世界中的一个实体,该实体是动态行为的一种信息表述。对于系统输出数据流的分离,JSD方法未加以说明。
3) 建立顺序进程
JSD方法将软件系统输入数据流的内含——客观世界及其动态行为称为软件系统的主题,而软件系统的功能则是根据系统的输入数据产生系统的输出数据。JSD方法在计算机中用信息处理的顺序进程,模拟系统主题中客观实体的行为,建立系统主题的计算机仿真模型,为产生系统输出数据的软件系统中的功能进程提供所需的输入数据。顺序进程、功能进程和它们之间数据通信的说明构成了完整、详尽的软件系统说明,JSD方法以此为依据,形成最终形式的、可在目标计算机环境中有效、方便运行的软件系统。
JSD涉及的活动几乎覆盖整个软件生命期,它强调需求分析和规格说明,也包括设计和编程,直至最终实现一个可运行的目标系统,是比较完整的系统开发方法。此外,JSD方法对需求的描述特别强调操作之间的时序性,所以它应用于时序特点较强的系统,包括数据处理系统和一些实时控制系统。
3. JSD方法的特点
JSD方法有如下特点:
(1) 建立现实世界的模型,确定用户的功能需求。现实世界的模型和用户功能需求之间是密切联系的,模型隐含了用户的各种功能。功能可从模型中自然地导出,是多变的,但模型却是较稳定的。所以,JSD的这一特色既有利于理解需求,又有助于以后的维护。
(2) 用顺序进程的网络描述需求。JSD用顺序进程描述现实中的实体和动作,用顺序进程网络描述现实世界的模型,这里“进程”概念与操作系统中的“进程”术语类似。
(3) JSD描述的需求原则上是可以直接执行的。JSD用顺序进程网络和纲要逻辑描述需求,其操作语义是确定的,所以原则上可以执行,即采用人工或自动的手段,可以从需求直接建立可运行的系统原型。因此,用JSD可实现快速原型。
(4) 开发过程不再沿用分析、设计及编程的模式,而是突出需求分析,把编程分散在各个步骤中陆续进行。
3.2 JSD的基本概念
1. 现实和系统
“现实”和“系统”是既联系又区别的两个概念,现实是客观存在的物质世界,如XX公司,人、才、物等;系统是通过开发活动试图获得的目标,如 XX公司管理信息系统。开发工作完成后系统将嵌入到现实中投入运行。显然,系统是现实的一个模型,它反映现实中发生的动作。为使系统能反映现实,现实需同系统发生联系,联系通过穿越系统边界的输入和输出信息实现。
2. 顺序进程
现实中的实体及其按时序执行的动作的表述就是顺序进程。现实中有实体存在,如银行系统中,有帐户实体。每个实体按某种时序执行动作,每个实体有各自的属性,属性因动作的发生而随时变化。如帐户甲7月里日开户,存款700元,7月2日取款200元,则帐户甲所持余款在取款后变为500元。
JSD用顺序进程模拟现实中的实体及其动作,而进程间的联系模拟实体间的交互作用,因而可以用一组顺序进程组成的网络构成现实的一个模型。
3. 进程间的联系
现实中的实体间有相互联系,所以其模型中的进程间亦需相互联系。JSD中,进程间用数据流方式或状态向量方式联系,前者通常用于实体向另一个进程发送数据,后者通常用于一个进程读另一进程的内部状态,状态向量就是指一个进程的所有内部状态。
4. 模型和功能
由于模型反映了现实,所以系统功能可以在模型的基础上描述。功能通常是系统应该输出什么信息,简单的系统功能在模型基础上描述,复杂功能则还需在模型上增加功能进程来描述。
9.3.3 JSD开发步骤
JSD把软件开发过程组织成6步,前5步组成了系统的需求说明阶段,第6步为系统的实现阶段。
1. 实体动作步
实体动作步是通过列出系统所关心的客观实体和其执行或承受的动作来定义系统主题的范围,即定义系统所感兴趣的客观世界域。
如餐厅业务中,实体有顾客(动作顺序是进餐厅、就座、订菜、用餐。付款及离开)、服务员(动作顺序有上班、送菜单、送饭菜、清理及下班)、会计和厨师等。
2. 实体结构步。
实体结构步是用Jackson图来描述每个实体执行的动作及其时序,产生一组描述实体进程的Jackson结构图。
餐厅业务中有顾客进程、会计进程等.会计进程如图9.6所示。
图9.6 会计进程
3. 初步模型步
初步模型步是用顺序进程网络构成现实的模型,并把模型同现实联系起来以实现两者间的同步。用纲要逻辑描述每个实体内部结构,产生描述模型的系统说明图和描述实体进程的纲要逻辑。在顺序进程网络中,用矩形框表示现实的实体、系统的顺序进程或功能进程,用圆圈表示数据流,用菱形表示状态向量,它们之间的连线表示实体与进程的联系。在餐厅业务的问题中,我们感兴趣的是会计进程,通过该进程的动作,可知餐厅每天的收入,餐厅业务的初始模型如图9.7所示。
图9.7 初始模型
会计进程的纲要逻辑是:
会计进程seq
read C;
记帐:iter while(有费用发生)
费用处理sel 进餐费
进餐费收入处理;
alt 原料费
原料费支出处理;
alt 人工费
人工费支出处理;
费用处理end
read C;
记帐:end
结帐
会计进程end
4. 功能步
功能步是在初始模型的基础上描述系统的功能,产生完善的系统说明图和完善的纲要逻辑。
5. 性能步
性能步考虑并描述系统的性能需求,确定系统对实现世界的滞后允许达到何种程度,即确定系统的响应时间。
6. 实现步
实现步考虑目标计算机环境的各种物理限制和系统的性能需求,运用各种实现转换技术.将软件系统说明转换为可在目标计算机环境中有效、便利运行的软件系统。
3.4 JSD应用示例
1) 问题陈述
公园租船管理处负责租船给游客在湖面上游玩。每次游客游玩后还船。该管理处职员要求计算机在每天工作结束时产生一天中游客总的租船次数和总的租船时间的报告。
2) 实体动作步
实体:游客
实体标识符:游客姓名
动作:租船。动作属性:船编号、租用时间(开始时间)
还船。动作属性:船编号。退还时间(结束时间)
输出:租船总次数
总的租船时间T=T+∑还船时间-∑租船时间
3) 实体结构步
实体结构如同9.8所示。
图9.8 实体结构
4) 初始模型步
用系统说明图来描述初始模型如图9.9所示。系统说明图即为顺序进程网络。
图9.9 系统说明图
5) 功能步
游客进程和职员进程的纲要逻辑描述如下:
游客1进程seq
session_time:=0;
read C;
租船seq
session_time:=session_time一租船时间;
租船end
read C;
还船seq
session_time:=session_time+还船时间;
还船end
游客1进程end
职员进程iter
报告seq
read REQ ;
totaltime:=0 ;number:=0;
get CV;
处理租船 iter while(not end_of_CVs)
totaltime:= totaltime+session_time;
number:=number+1;
get CV;
处理租船end
write Reportline(‘总租船次数’,numbrr,‘总租船时间’,totaltime);
报告end
职员进程end
6) 实现步
前面形成的软件系统说明中,游客进程有成千上万个,可能是并发的,这不能在有限的处
理机上运行,因此设置一调度程序,处理多进程的运行调度。
若在计算机中保存所有进程的正文拷贝和运行状态向量,则将占用大量存储空间,因此将正文同其状态向量分离保存。因同一类进程的动作相同,则只保存一个正文拷贝,当某一进程激活时,将该类进程正文同该进程的状态向量重新结合,占用处理机资源,形成一个活动进程。
将上述软件系统说明用系统实现图来实现,如图9.10所示。
图9.IO 系统实现图
四 小 结
本章所讲的内容小结如下:
(1) JSP方法主要体现程序结构的设计,不明确地划分软件概要设计和详细设计的两个阶段。根据JSP的规则直接推出程序结构。可以将它与SD方法相结合,用SD方法设计体系结构,用JSP方法设计它的局部模块。
(2) JSP方法主要用于规模不大的数据处理系统,输入、输出数据结构能较容易地描述出来的情况。对于较大的系统,涉及很多输入、输出数据,其结构又不互相对应的情况,用JSP方法解决要困难一些。
(3) JSD方法开创性地进行了对客观世界及其同软件间关系的研究。JSD方法第一次揭示了某些软件概念(输入数据)同客观世界(用户业务)概念的一种内在联系,指出所谓软件系统的输入数据,实际上是系统所关心的客观世界动态行为的一种计算机所能接受的信息的表述;同时使这部分软件系统概念结构(JSD方法中的模型结构)保持其所内含的客观世界概念的自然结构,因此极大地提高了软件系统结构的正确性、稳固性、可理解性和可维护性。
(4) JSD明确了软件系统说明决策同软件系统实现决策的界限。传统的应用软件开发方法在软件系统说明中只包含软件系统是做什么的说明,而不包含软件系统是怎么做的逻辑说明,这一说明决策是同软件系统的实现决策一起在软件设计和编码阶段才开发的。由于这样形成的软件系统不能构成一完整、可工作的系统,因此造成软件系统理解、移植和实现的困难。事实上两种完全不同的开发决策混杂在一起进行,人为地增加了软件系统开发的复杂性,而JSD方法由于明确划分了软件系统说明决策同软件系统实现决策的界限而克服了以上缺陷。
(5) JSD对客观世界及其同软件间关系的认识不完整。JSD方法并未揭示算法、输出数据同客观世界概念的内在联系。这使得 JSD方法中功能进程的开发仍基于JSP的程序设计技术来进行,开发出的功能进程结构完全是计算机算法性的,它与顺序进程不同,顺序进程是由一系列动作组织成的结构,这也使得JSD方法中输出数据的组织无一定规则,其划分基本上由开发者随意进行,从而软件系统中功能进程的组织也是无章法的。其中顺序进程和功能进程概念和结构上不一致会导致某些应用软件系统开发时的严重困难。
(6) JSD方法未能充分利用新发展的软件概念,致使确立的软件系统实现结构过于复杂,不易为软件开发者接受。
(7) 软件说明结构的描述技术不恰当。软件系统说明的作用在于提供不受具体目标计算机因素影响、供所有开发者使用的标准的软件系统说明。而JSD方法却采用第三代语言等目标机程序设计语言来描述软件系统说明,这不利于软件开发者对系统的理解和他们之间的通信交流,因为大多数软件开发者使用掌握的第三代语言并不相同。同时第三代语言由于比较低级并不适于对系统说明提供最直接有效的支持。
JSD方法的上述这些缺陷在很大程度上限制了人们实际运用JSD方法的热情。
第三讲 软件设计
大连海事大学计算机学院软件工程研究室 蒋 波
软件设计阶段要解决的问题是“How to do”的问题。就是说,需将整个系统划分出系统的物理组成元素(程序、文件、DB、人工过程、文档)。
软件设计分为基本设计和详细设计两个部分。基本设计的主要工作是确定系统的结构、进行模块化划分、确定每一个模块的功能、规定每一个模块的接口及调用关系、确定全局数据结构等;详细设计的主要工作是为每一个模块设计其实现细节并确定各个局部数据结构。
软件设计过程是:首先在需求描述的基础上设想实现目标系统的各种可能的方案,然后从这些可供选择的方案中选取若干个合理的方案,为每个合理的方案都准备一份系统流程图、列出组成系统的所有物理元素、分别进行成本/效益分析、制定实现这个方案的进度计划等。最后通过综合比较分析这些合理方案,从中选出一个最佳方案推荐给用户。如果用户接受了推荐的方案,分析员应该进一步为这个最佳方案设计软件结构。通常,设计出初步的软件结构后,还需要多方改进以便得到更合理的结构。在此基础上进行必要的数据库设计,确定测试要求并且制定测试计划。
总体设计的目的就是要站在全局高度,在较抽象的层次上分析对比多种可能的系统实现方案和软件结构,从中选出最佳方案和最合理的软件结构,从而用较低成本开发出较高质量的软件系统。通常由两个主要阶段组成:系统设计——确定系统的具体实现方案;结构设计——确定软件结构。
一. 基本设计(总体设计)
1. 软件设计过程(基本任务)
1) 依据需求分析的基础设想可供选择的方案;
依据DFD设计各种可能的处理组合——方案。在这个过程中,分析员依据各个处理边界逐个设想可供选择的方案,并不评价各种方案的优劣。
2) 选取合理的方案;
通常选取低成本、中成本、高成本的三种方案,根据可行性研究阶段所理解的用户的各种需求进行选择。对每一个合理的方案,准备系统流程图、组成系统的物理元素清单、成本和效益分析、实现系统的进度计划等。
成本估算的方法:代码行价格技术、任务分解技术、FP技术、自动估算技术(分别解释)。
3) 推荐最佳方案;
分析员应该综合分析对比各种合理方案的利弊,在合理的方案中找最佳方案并制定详细的执行计划。
4) 功能分解;
1.结构设计:确定组成各功能服务的模块以及模块与模块之间的关系。
2.过程设计:确定每个模块的内部处理过程。
通过分解系统的各个复杂功能,将系统的功能服务细化到很容易实现的地步。在面向数据流的设计方法中,这个过程采用细化数据流图的方法实施。
结构设计是总体设计阶段的任务,过程设计是详细设计阶段的任务。为确定软件结构,首先需要从实现角度把复杂的功能进一步分解。分析员结合算法描述仔细分析数据流图中的每个处理,如果一个处理的功能过分复杂,必须把它的功能适当地分解成一系列比较简单的功能。一般说来,经过分解之后应该使每个功能对大多数程序员而言都是明显易懂的。功能分解导致数据流图的进一步细化,同时还应该用IPO图或其地适当的工具简要描述细化后每个处理的算法。
5) 设计软件结构;
通常一个模块完成一个适当的子功能。用层次图或结构图来清楚地描述各功能模块之间的调用关系。(举例说明层次图或结构图的例子)。
如果数据流图已经细化到适当的层次,则可以直接从数据流图映射出软件结构,我们将以面向数据流的设计方法为例详细介绍该过程。
6) 设计数据库结构;
模式设计;子模式设计;完整性与安全性设计;优化。
7) 制定测试计划;
在软件开发的早期指定测试计划,能够促使设计人员在设计软件时充分注意提高软件的可测试性。
8) 书写文档;
完成下列文档的书写:
系统说明:包括系统流程图、系统构成方案、组成系统的物理元素清单、成本/效益分析;最佳方案的描述与细化的DFD;软件结构图;用IPO图或其他工具(例如,PDL语言)简要描述的各个模块的算法;模块间的接口关系以及需求、功能和模块三者之间的交叉参照关系等等。
用户手册:修改在系统分析阶段所形成的用户手册。
测试计划:包括测试策略、测试方案、预期的测试结果、测试的进度计划等。
详细实施计划:里程表,软件项目管理的进度管理工具。
数据库设计结果:包括数据库管理系统的选择、模式、子模式、完整性和安全性、以及优化方法,数据字典等。
9) 审查与复审:技术人员的技术审查与管理人员的复审。
2. 软件设计的概念和原理
1) 模块化:将复杂功能进行分解的过程。
模块是数据说明、可执行语句等程序对象的集合,它是单独命名且可通过名字来访问的。例如,过程、函数、子程序、宏等等都可作为模块。模块化就是把程序划分成若干个模块,每个模块完成某个子功能的过程。把这些模块集总起来组成一个整体,可以完成指定的功能满足问题的要求。
设函数C(x)定义问题x的复杂程度,函数E(x)确定解决问题x需要的工作量(时间)。对于两个问题P1和P2,如果
C(P1)> C(P2)
显然,E(P1)> E(P2)
根据人类解决一般问题的经验,另一个有趣的规律是
C(P1 + P2) > C(P1)+ C(P2)
也就是说,如果一个问题由P1和P2两个问题组合而成,那么它的复杂程序大于分别考虑每
个问题时的复杂程度之和。
综上所述,得到下面的不等式
E(P1 + P2)> E( P1)+ E( P2)
但是,如果这样无限制地分割下去,是不是意味着开发软件所需的工作量也就小得可以忽略了呢。事实上,当模块数目增加时每个模块的规模将减小,开发单个模块需要的成本(工作量)确实减少了,但是随着模块数目增加,设计模块间接口所需要的工作量也将增加。
2) 抽象
在模块化求解问题时,可以得到许多抽象的层次。在抽象的最高层次使用问题环境的语言,以概括的方式叙述问题的解法;在较低抽象层次采用更过程化的方法,把面向问题的术语和面向实现的术语结合起来叙述问题的解法;最后,在最低的抽象层次用可以直接实现的方式叙述问题的解法。
软件工程过程的每一步都是对软件解法的抽象层次的一次精化。在可行性研究阶段,软件作为系统的一个完整部件;在需求分析期间,软件解法是使用在问题环境内熟悉的方式描述的;当我们由总体设计向详细设计过渡时,抽象的程度也就随之减少了;最后,当源程序写出来以后也就达到了抽象的最低层。
逐步求精和模块化的前提是抽象。从事物的本质出发暂时忽略一些细微的差异。这也是设计重用软件的基础
3) 信息隐蔽和局部化
将与模块相关联属性局限在模块的内部,尽量减少模块间的联系。
信息隐蔽原理指出:应该这样设计和确定模块,使得一个模块内包含的信息(过程和数据)对于不需要这些信息的模块来说,是不能访问的。
模块独立的概念是模块化、抽象、信息隐蔽和局部化概念的直接结果。
开发具有独立功能而且和其他模块之间没有过多的相互作用的模块,就可以做到模块独立。换句话说,希望这样设计软件结构,使得每个模块完成一个相对独立的特定子功能,并且和其他模块之间的关系很简单。
为什么模块的独立性很重要呢?主要有两条理由:第一有效的模块化(即具有独立的模块)的软件比较容易开发出来。这是由于能够分割功能而且接口可以简化,当许多人分工合作开发同一个软件时,这个优点尤其重要。第二,独立的模块比较容易测试和维护。这是因为相对说来,修改设计和程序需要的工作量比较小,错误传播范围小,需要扩充功能时能够“插入”模块。总之,模块独立是好设计的关键,而设计只是决定软件质量的关键环节。
模块的独立程度可以由两个定性标准度量,这两个标准分别称为内聚和耦合。耦合衡量不同模块彼此间互相依赖(连接)的紧密程度;内聚衡量一个模块内部各个元素彼此结合的紧密程度。以下分别详细阐述。
4) 模块独立及其度量
耦合 衡量不同模块彼此相互依赖的紧密程度的一种度量
内聚 衡量模块内部各个元素彼此结合的紧密程度的一种度量
耦合方式:(7种)每种耦合尽量举例说明。
非直接耦合 两个模块没有直接的联系,互相都不依赖于对方而能独立地工作; 数据耦合 两个模块借助于参数表传递简单数据;
标记耦合 两个模块借助于参数表传递数据结构的一部分;
控制耦合 两个模块间传递的信息中包含有用于控制模块内部逻辑的控制信息; 外部耦合 模块与软件以外的环境有关;
公共耦合 多个模块引用同一全局数据区的模式;
内容耦合 两个模块间出现了下列情况之一:
a) 一个模块访问另一个模块的内部数据;
b) 一个模块不通过正常的入口转到另一个模块的内部;
c) 两个模块有一部分程序代码重叠(汇编语言程序)
d) 一个模块有多个入口
自上而下,其耦合程度越来越强。
内聚方式:(7种):每种内聚尽量举例说明。
偶然内聚 一个模块完成一组任务,这组任务彼此间即使有关系,其关系也是松散
的;
逻辑内聚 一个模块完成逻辑上相关的一组任务;
瞬时内聚 一个模块所包含的任务必须在同一时间间隔内执行(如初始化模块); 过程内聚 一个模块的处理元素是相关的,而且必须按特定的次序执行;
通信内聚 一个模块的所处理元素集中在一个数据结构的区域上(如所有处理元素
使用同一输入数据);
顺序内聚 一个模块的处理元素是相关的且必须顺序执行;
功能内聚 一个模块完成一个单一的功能,模块中的各部分在此目标下协同工作且
都是完成这一功能不可缺少的;
自上而下,其内聚程度越来越强。
3. 软件设计的原则
1) 满足信息隐蔽原则;
2) 尽量做到高内聚、低耦合;
3) 模块的大小适中,以完成一个相对独立的功能为宜;
4) 模块的调用深度不宜过大;
5) 模块的扇入应尽量大,而扇出不宜过大;
6) 设计单入口和单出口的模块;
7) 模块的作用域应在控制域之内;
模块的作用域定义为受该模块内一个判定影响的所有模块的集合。
模块的控制域定义为该模块本身及直接或间接从属于该模块的模块集合。
模块M的作用域为{A,B,C,D,E,F}
模块M的控制域为{M,A,B,C,D,E,F}
在一个设计得很好的系统中,所有受判定影响的模块应该都从属于做出判定的那个模块,最好局限于做出判定的那个模块本身及它的直属下级模块。例如,图中模块A做出的判定只影响模块B,那么是符合这条规则的。但是,如果模块A做出的判定同时还影响模块G中的处理过程,那就不满足这个原理了。这样做的坏处是:首先,这样的结构使得软件难于理解。其次,为了使得A中的判定能影响G中的处理过程,通常需要在A中给一个标记用以记录判定的结果,并将这个标记传递给A和G的公共上级模块M,再由M把它传给G。这个标记是控制信息而不是数据,因此将使模块间出现控制耦合。
怎样修改软件结构才能使作用域是控制域的子集呢?一个方法是把做判定操作上移,例如,把判定从模块A中移到模块M中。另一个方法是把那些在作用域中但不在控制域内的模块移到控制域内,例如,把模块G移到模块A的下面,成为它的直属下级模块。
到底采用哪种方法改进软件结构,需要根据具体问题统筹考虑。一方面应该考虑哪种方法更现实,另一方面应该使软件结构能最好地体现问题原来的结构。
8) 模块的功能应该是可以预测的。
功能可预测是指对于相同的输入,应该得到相同的输出。
4. 图形工具(参见邓书P40-45)
1) 层次图和HIPO图
2) 结构图
5. 面向数据流的设计方法(结构化程序设计方法)
结构化设计方法SD是一种面向数据流的设计方法。它与结构化分析SA相衔接。SD采用结构图(Structure Chart-SC)来描述程序结构。
5.1 步骤:(参见流程图部分)
1)复查并精化DFD;
2)确定DFD的信息流类型(变换流或事务流);
3)根据数据流类型分别实施变换分析或事务分析;
4)根据软件设计原则对程序结构图作优化。
下图说明了面向数据流设计方法的过程
在一个设计得很好的系统中,所有受判定影响的模块应该都从属于做出判定的那个模块,最好局限于做出判定的那个模块本身及它的直属下级模块。例如,图中模块A做出的判定只影响模块B,那么是符合这条规则的。但是,如果模块A做出的判定同时还影响模块G中的处理过程,那就不满足这个原理了。这样做的坏处是:首先,这样的结构使得软件难于理解。其次,为了使得A中的判定能影响G中的处理过程,通常需要在A中给一个标记用以记录判定的结果,并将这个标记传递给A和G的公共上级模块M,再由M把它传给G。这个标记是控制信息而不是数据,因此将使模块间出现控制耦合。
怎样修改软件结构才能使作用域是控制域的子集呢?一个方法是把做判定操作上移,例如,把判定从模块A中移到模块M中。另一个方法是把那些在作用域中但不在控制域内的模块移到控制域内,例如,把模块G移到模块A的下面,成为它的直属下级模块。
到底采用哪种方法改进软件结构,需要根据具体问题统筹考虑。一方面应该考虑哪种方法更现实,另一方面应该使软件结构能最好地体现问题原来的结构。
8) 模块的功能应该是可以预测的。
功能可预测是指对于相同的输入,应该得到相同的输出。
4. 图形工具(参见邓书P40-45)
1) 层次图和HIPO图
2) 结构图
5. 面向数据流的设计方法(结构化程序设计方法)
结构化设计方法SD是一种面向数据流的设计方法。它与结构化分析SA相衔接。SD采用结构图(Structure Chart-SC)来描述程序结构。
5.1 步骤:(参见流程图部分)
1)复查并精化DFD;
2)确定DFD的信息流类型(变换流或事务流);
3)根据数据流类型分别实施变换分析或事务分析;
4)根据软件设计原则对程序结构图作优化。
下图说明了面向数据流设计方法的过程
5.2 例子
1)变换分析
确定输入流和输出流,孤立出变换中心;
第一级分解;
第二级分解。
2)事务分析
确定事务中心和每条活动流信息;
将事务流型DFD映射成高层的程序结构;
进一步分解。
二. 详细设计
1. 结构化程序设计
1) 顺序结构;
2) 分支结构;
3) 循环结构;
4) GOTO语句的讨论
2. 详细设计工具
1) 程序流程图
2) 盒图(N-S图)
3) PAD图
4) 判定表 (参见邓书P45)
5) 判定树 (参见邓书P45)
6) 过程设计语言PDL(Process Design Language)
3. 详细设计说明书
1) 概要功能说明;
2) 画面格式设计与说明;
3) 数据关联图;
4) 输入/输出数据项的详细描述;
5) 处理功能逻辑说明(流程图等);
6) 画面迁移(功能逻辑关系的反映)。
4.详细设计说明书例子(参见附加资料)
三、Jackson方法
下面介绍一种面向数据结构的软件开发方法,它包括Jackson于20世纪70年代提出的JSP(Jackson Structured Programming)和80年代提出的JSD(Jackson System Development)。
早期的Jackson方法用于开发规模较小的数据处理系统的设计,80年代后期,Jackson在JSP的基础上扩展成了一种系统的开发方法,即JSD。JSD主要以活动事件为中心,通过由一串活动顺序组合构成的进程,建立系统模型,最后实现该模型。
一 概述
1. 产生
JSP方法是一种面向数据结构,以数据驱动的程序设计方法。它是20世纪70年代由M.Jackson提出的。该方法在设计较简单的数据处理系统时特别方便,当设计比较复杂的程序时常常遇到输入数据可能有错、条件不能预先测试和数据结构冲突等问题。为了克服这个困难,1978~1981年间Jackson与J.R.Cameron共同开发出了JSD方法,增加了一系列比较复杂的辅助技术,使之适合于大型系统的开发。它以事件为驱动,是基于进程模型的。
2. 基本思想
程序和数据的密切关系可追溯到计算技术的起源,把程序看成数据,把数据看成程序,在20世纪60年代,有一派人主张,内在数据结构是至关紧要的,可利用输入数据结构和输出数据结构来推导出程序结构。在许多领域中,存在着明显的层次信息结构,层次数据组织常常和使用这些数据的程序十分相似,数据的结构十分出色地指示了程序的结构。面向数据结构的设计方法就是利用这些结构作为开发软件的基础。
3. 设计和数据结构的关系
数据结构影响软件结构和过程,程序加工的是数据,程序表述的算法在很大程度上依赖于作为基础的数据结构。如记录、表及结构等类型的数据,分量与分量之间是一种顺序结构,程序处理必然是顺序的控制结构;数组、文件每个分量占据的空间一样大且连续存放,程序处理必然是循环的控制结构;变体记录、联合等类型的数据是一种选择覆盖的结构,程序处理必然是分支的控制结构;数据结构分层次(如文件由许多记录组成),程序结构也必然分层。因此,数据结构不但影响程序的结构,也影响着程序的处理过程。所以70年代中期出现了“面向数据结构”的设计方法,其中有代表性的是由M.Jackson提出的Jackson方法和由J.Warnier提出的Warnier方法。
4. SD方法和JSP方法的异同
面向数据流的设计(SD方法)和面向数据结构的设计(JSP方法)的共同点都是数据信息驱动的,都试图将数据表示转换成软件表示,不同之处在于面向数据结构的设计不利用数据流图,而根据数据结构的表示来设计。JSP方法定义了一组以数据结构为指导的映射过程,它根据输入、输出的数据结构,按一定的规则映射成软件的过程描述,最终目标是生成软件过程的描述,即程序结构,而不是软件的体系结构。而SD方法是根据数据流图来设计,最终目标是建立软件体系结构的描述,即软件模块的层次结构。
5. JSP方法的优缺点
JSP方法的优点:简单,适合于规模不大的系统,建立了问题的数据结构之后,可直接推导出相应的程序结构。
JSP方法的局限性:不适合于大系统,当输入数据结构与输出数据结构不相同且无对应关系时,难于应用。当数据结构发生变化时,程序结构也发生变化,一般是总体上用SD方法,局部范围用JSP方法。
二 JSP 方法
JSP是为中小型数据处理系统设计程序结构的一种方法,其设计原则是“程序结构同数据结构相对应”。JSP的描述工具有Jackson图和纲要逻辑,纲要逻辑是一种描述算法过程的语言,它分别用seq,iter和 sel-alt三类关键字描述顺序、重复和选择三种结构。
2.1 Jackson图
Jackson图是JSP方法的描述工具,在分析、确定问题的数据结构后,用Jackson图来描绘问题的数据结构。
1. Jackson图的表示
虽然程序中实际使用的数据结构种类繁多,但是它们的数据元素彼此间的逻辑关系却只有顺序、选择和重复三种,因此,逻辑数据结构也只有这三种。
1) 顺序结构
顺序结构的数据由一个或多个数据元素组成,每个元素按确定次序出现一次。如图9.1(a)中的A是一个顺序结构,指出基本成份B,C,D顺序组成。注意,这里的A并非模块,它既可以是数据(表示数据结构时),又可以是程序(表示程序结构时),而B,C,D仅是A的成份,上、下层是“组成”的关系,A中除了B,C,D外不包含其他代码,不同于Yourdon方法的软件结构。
2) 选择结构
选择结构的数据包含两个或多个数据元素,每次使用这个数据时按一定条件从这些数据元素中选择一个。如图9.1(b)中的A是一个选择结构,由数据元素 B,C或 D组成。
3) 重复结构
重复结构的数据,根据使用时的条件由一个数据元素出现零次或多次构成。如图9.l(c)所示,表示A由多个数据元素B组成。
(a)顺序结构; (b)选择结构; (c)重复结构
图 9.1 Jackson图
2. Jackson图的优点
Jackson图具有如下优点:
(1) 便于表示层次结构,是对结构进行自顶向下分解的有力工具。
(2) 形象直观可读性好。
(3) 既能表示数据结构也能表示程序结构(因为程序结构也只有上述三种基本类型)。
3. Jackson图应用的示例
某仓库管理系统每天要处理大批由单据所组成的事务文件。单据分为订货单和发货单两种,每张单据由多行组成,订货单每行包括零件号、零件名、单价及数量等4个数据项,发货单每行包括零件号、零件名及数量等3个数据项,用Jackson结构图表示该事务文件的数据结构。图9.2为该事务文件的数据结构。
图9.2 事务文件的Jackson结构图
2.2 纲要逻辑
纲要逻辑是类似于伪码的一种语言表示工具,与Jackson结构图对应,用于将Jackson结构图表示的程序结构转换为语言表示。
图9.l中对应的纲要逻辑为:
(1)顺序结构:
A seq
B
C
D
A end
(2) 选择结构:
A sel 条件 1
B
alt 条件2
C
alt 条件3
D
A end
(3) 重复结构:
A iter until(或while)条件
B
A end
2.3 开发步骤
JSP方法基本由下列5个步骤组成:
(1) 分析并确定输入数据和输出数据的逻辑结构,并用Jackson图描绘这些数据结构。
(2) 找出输入数据结构和输出数据结构中有对应关系的数据单元。所谓有对应关系是指有直接的因果关系,在程序中可以同时处理的数据单元(对于重复出现的数据单元必须是重复的次序和次数都相同才可能有对应关系)。
(3) 用下列3条规则从描绘数据结构的Jackson图导出描绘程序结构的Jackson图; ① 为每对有对应关系的数据单元,按照它们在数据结构图中的层次和在程序结构图的相应层次画一个处理框(如果这对数据单元在输入数据结构和输出数据结构中所处的层次不同,则和
它们对应的处理框在程序结构图中所处的层次与它们之中在数据结构图中层次低的那个对应)。
② 根据输入数据结构中剩余的每个数据单元所处的层次,在程序结构图的相应层次分别为它们画上对应的处理框。
③ 根据输出数据结构中剩余的每个数据单元所处的层次,在程序结构图的相应层次分别为它们画上对应的处理框。
(4) 列出所有操作和条件(包括选择条件和重复结束条件),并把它们分配到程序结构图的适当位置。
(5) 用纲要逻辑表示程序。
2.4 JSP方法应用示例
现举例说明JSP方法设计过程。
1) 问题陈述
某仓库存放多种零件(如 P1,P2,„„),每个零件的每次进货、发货都有一张卡片作出记录,每月根据这样一叠卡片打印一张月报表。报表每行列出某种零件本月库存量的净变化。用JSP方法对该问题进行设计。
2) 建立输入、输出数据结构
建立输入、输出数据结构的步骤如下:
(1) 输入数据:根据问题陈述,同一种零件的进货、发货状态不同,每月登记有若干张卡片。把同一种零件的卡片放在一起组成一组,所有的卡片组按零件名排序。所以输入数据是由许多零件组组成的文件,每个零件组有许多张卡片,每张卡片上记录着本零件进货或发货的信息。因此输入数据结构的Jackson图为图9.3(a)。
(2) 输出数据:根据问题陈述,输出数据是一张如图9.3*)的月报表,它由表头和表体两部分组成,表体中有许多行,一个零件的净变化占一行,其输出数据结构的Jackson图为图
9.3(b)。
3) 找出输入、输出数据结构中有对应关系的单元
月报表由输入文件产生,有直接的因果关系,因此顶层的数据单元是对应的。表体的每一行数据由输入文件的每一个“零件组”计算而来,行数与组数相同,且行的排列次序与组的排列次序一致,都按零件号排序。因此“零件组”与“行”两个单元对应,以下再无对应的单元。
图9.3 某仓库系统输入、输出数据结构
(a)输入数据结构;(b)输出数据结构;(c)输出表
4) 导出程序结构
找出对应关系后,根据以下规则导出程序结构:对于输入数据结构与输出数据结构中的数据单元,每对有对应关系的数据单元按照它们所在的层次,在程序结构图适当位置合画一个处理框,无对应关系的数据单元,各画一个处理框。
根据以上规则,画出的程序结构图如图9.4所示。
在图9.4的程序结构的第4层增加了一个“处理零件组”的框,因为改进的Jackson图规定顺序执行的处理中不允许混有重复执行和选择执行的处理。增加了这样一个框,使符合该规定,同时也提高了结构图的易读性。
图9.4 某仓库系统程序结构
5) 列出并分配操作与条件
为了对程序结构作补充,要列出求解问题的所有操作和条件,然后分配到程序结构图 的适当位置,就可得到完整的程序结构图。
(1)本问题的基本操作列出如下:
A、终止 B、打开文件 C、关闭文件 D、打印字符行 E、读一张卡 F、产生行结束符 G、累计进货量 H、累计发货量 I、计算净变化 J、置零件组开始标志
(2) 列出条件如下:
I(l):输入条件未结束 I(2):零件组未结束 S(3):进发货标志
将操作与条件分配到适当位置的程序结构图如图9.5所示。
图9.5 分配操作后的程序结构图
在分配操作时注意:为了能获得重复和选择的条件,Jackson建议至少超前读一个记录,以便使得程序不论在什么时候判定,总有数据已经读入,并做好使用准备。因此在图9.5中,将操作E(读一张卡)放在打开文件之后,同时在处理完一张卡片后再读一次。
6) 用纲要逻辑写出程序
Jackson方法中的纲要逻辑与Jackson所示的程序结构图完全对应,用纲要逻辑写出程序的过程,实际上就是自顶向下用这些纲要逻辑替换Jackson图中每个处理框的过程,每个处理框都看作是下层处理框及分配在上面的操作组成。
图9.5所示的程序结构的纲要逻辑为:
产生月报表 seq
打开文件
读一张卡
产生表头 seq
打印字符行
产生表头end
置零件组开始标志
产生表体 iter while输入文件未结束
由零件组产生输出行seq
处理零件组 iter while零件组未结束
处理卡片sel进货标志
处理进货seq
累计进货量
处理进货end
alt发货标志
处理发货seq
累计发货量
处理发货end
处理卡片end
读一张卡
处理零件组end
产生零件名seq
打印字符行
产生零件名end
产生净变化seq
计算净变化
打印字符行
产生净变化end
换行
置零件组开始标志
由零件组产生输出行end
产生表体end
关闭文件
终止
产生月报表end
用纲要逻辑书写程序可以很方便地转换成源代码,还可以检查前面步骤的错误。如果分配操作不正确或者结构图不正确,都难以写出它的纲要逻辑。
2.5 结构冲突问题
JSP方法适用于输入数据和输出数据结构之间有对应关系的问题求解。但有些情况下,输入数据和输出数据结构之间找不到对应关系,若仓库系统中的卡片不按零件名分组,而是按进货、发货的日期顺序排列,这样“零件组”与“行”就不对应了。输入数据与输出数据结构找不到对应关系的情况,称为结构冲突。对这种结构冲突的问题,Jackson提出了引入中间数据结构或中间文件的办法,将冲突部分分隔开来,建立多个程序结构,再利用中间文件把它们联系起来,构成一个系统的整体。
例如有一个卡片文件,存放一个矩阵,每张卡片包含矩阵的一行元素。要求按列打印该矩阵,即输出的每一行是矩阵的每一列元素。这个问题的输入数据与输出数据在结构上是冲突的,是次序冲突。解决的办法是构造两个程序结构,分别解决输入和输出的问题,在输入和输出之间增加一个分类程序,将输入产生的按行排列的矩阵转换成按列排列的矩阵,然后再输出。这个按列排列的矩阵即为中间数据结构或中间文件。
三、 JSD 方 法
3.1 JSD概述
1. JSD的产生
JSD方法是JSP的扩充,它是因JSP的缺陷而产生的。9.2节已经讲到JSP方法是基于输入数据结构和输出数据结构的对应复合而成程序结构的,但当要开发的系统十分庞大时,输入数据结构和输出数据结构之间就会出现大量复杂的、JSP难以对付的结构冲突问题,致使软件系统结构无法形成,因而它只是一种程序设计方法,只适用于小型程序的开发。
2. JSD的基本思想
1) 分而治之的原则
JSD则是采用“分而治之”的复杂性控制原则,将系统大量复杂的输入数据流和输出数据流分离为一些独立的、彼此无关联的、结构简单的输入数据流和一些独立的、彼此无关联的输出数据流,其中每一简单的输出数据流仅关联于少数几个简单的输入数据流。这样,一个错综复杂的庞大问题就转化为多个互不关联的独立的小型程序开发问题,这些小型程序在开发时不会出现复杂的结构冲突,即可直接使用JSP方法了。
2) 确定实体
对于系统输入数据流的分离,JSD方法追溯系统输入数据流的真正内含,即系统输入数据流是系统所关注的客观世界动态行为的一种信息表述。因此,JSD方法根据用户的专业知识,对客观世界行为进行自然划分,将系统输入数据流分离为多个彼此独立的输入数据流,其中每种独
立的输入数据流对应于客观世界中的一个实体,该实体是动态行为的一种信息表述。对于系统输出数据流的分离,JSD方法未加以说明。
3) 建立顺序进程
JSD方法将软件系统输入数据流的内含——客观世界及其动态行为称为软件系统的主题,而软件系统的功能则是根据系统的输入数据产生系统的输出数据。JSD方法在计算机中用信息处理的顺序进程,模拟系统主题中客观实体的行为,建立系统主题的计算机仿真模型,为产生系统输出数据的软件系统中的功能进程提供所需的输入数据。顺序进程、功能进程和它们之间数据通信的说明构成了完整、详尽的软件系统说明,JSD方法以此为依据,形成最终形式的、可在目标计算机环境中有效、方便运行的软件系统。
JSD涉及的活动几乎覆盖整个软件生命期,它强调需求分析和规格说明,也包括设计和编程,直至最终实现一个可运行的目标系统,是比较完整的系统开发方法。此外,JSD方法对需求的描述特别强调操作之间的时序性,所以它应用于时序特点较强的系统,包括数据处理系统和一些实时控制系统。
3. JSD方法的特点
JSD方法有如下特点:
(1) 建立现实世界的模型,确定用户的功能需求。现实世界的模型和用户功能需求之间是密切联系的,模型隐含了用户的各种功能。功能可从模型中自然地导出,是多变的,但模型却是较稳定的。所以,JSD的这一特色既有利于理解需求,又有助于以后的维护。
(2) 用顺序进程的网络描述需求。JSD用顺序进程描述现实中的实体和动作,用顺序进程网络描述现实世界的模型,这里“进程”概念与操作系统中的“进程”术语类似。
(3) JSD描述的需求原则上是可以直接执行的。JSD用顺序进程网络和纲要逻辑描述需求,其操作语义是确定的,所以原则上可以执行,即采用人工或自动的手段,可以从需求直接建立可运行的系统原型。因此,用JSD可实现快速原型。
(4) 开发过程不再沿用分析、设计及编程的模式,而是突出需求分析,把编程分散在各个步骤中陆续进行。
3.2 JSD的基本概念
1. 现实和系统
“现实”和“系统”是既联系又区别的两个概念,现实是客观存在的物质世界,如XX公司,人、才、物等;系统是通过开发活动试图获得的目标,如 XX公司管理信息系统。开发工作完成后系统将嵌入到现实中投入运行。显然,系统是现实的一个模型,它反映现实中发生的动作。为使系统能反映现实,现实需同系统发生联系,联系通过穿越系统边界的输入和输出信息实现。
2. 顺序进程
现实中的实体及其按时序执行的动作的表述就是顺序进程。现实中有实体存在,如银行系统中,有帐户实体。每个实体按某种时序执行动作,每个实体有各自的属性,属性因动作的发生而随时变化。如帐户甲7月里日开户,存款700元,7月2日取款200元,则帐户甲所持余款在取款后变为500元。
JSD用顺序进程模拟现实中的实体及其动作,而进程间的联系模拟实体间的交互作用,因而可以用一组顺序进程组成的网络构成现实的一个模型。
3. 进程间的联系
现实中的实体间有相互联系,所以其模型中的进程间亦需相互联系。JSD中,进程间用数据流方式或状态向量方式联系,前者通常用于实体向另一个进程发送数据,后者通常用于一个进程读另一进程的内部状态,状态向量就是指一个进程的所有内部状态。
4. 模型和功能
由于模型反映了现实,所以系统功能可以在模型的基础上描述。功能通常是系统应该输出什么信息,简单的系统功能在模型基础上描述,复杂功能则还需在模型上增加功能进程来描述。
9.3.3 JSD开发步骤
JSD把软件开发过程组织成6步,前5步组成了系统的需求说明阶段,第6步为系统的实现阶段。
1. 实体动作步
实体动作步是通过列出系统所关心的客观实体和其执行或承受的动作来定义系统主题的范围,即定义系统所感兴趣的客观世界域。
如餐厅业务中,实体有顾客(动作顺序是进餐厅、就座、订菜、用餐。付款及离开)、服务员(动作顺序有上班、送菜单、送饭菜、清理及下班)、会计和厨师等。
2. 实体结构步。
实体结构步是用Jackson图来描述每个实体执行的动作及其时序,产生一组描述实体进程的Jackson结构图。
餐厅业务中有顾客进程、会计进程等.会计进程如图9.6所示。
图9.6 会计进程
3. 初步模型步
初步模型步是用顺序进程网络构成现实的模型,并把模型同现实联系起来以实现两者间的同步。用纲要逻辑描述每个实体内部结构,产生描述模型的系统说明图和描述实体进程的纲要逻辑。在顺序进程网络中,用矩形框表示现实的实体、系统的顺序进程或功能进程,用圆圈表示数据流,用菱形表示状态向量,它们之间的连线表示实体与进程的联系。在餐厅业务的问题中,我们感兴趣的是会计进程,通过该进程的动作,可知餐厅每天的收入,餐厅业务的初始模型如图9.7所示。
图9.7 初始模型
会计进程的纲要逻辑是:
会计进程seq
read C;
记帐:iter while(有费用发生)
费用处理sel 进餐费
进餐费收入处理;
alt 原料费
原料费支出处理;
alt 人工费
人工费支出处理;
费用处理end
read C;
记帐:end
结帐
会计进程end
4. 功能步
功能步是在初始模型的基础上描述系统的功能,产生完善的系统说明图和完善的纲要逻辑。
5. 性能步
性能步考虑并描述系统的性能需求,确定系统对实现世界的滞后允许达到何种程度,即确定系统的响应时间。
6. 实现步
实现步考虑目标计算机环境的各种物理限制和系统的性能需求,运用各种实现转换技术.将软件系统说明转换为可在目标计算机环境中有效、便利运行的软件系统。
3.4 JSD应用示例
1) 问题陈述
公园租船管理处负责租船给游客在湖面上游玩。每次游客游玩后还船。该管理处职员要求计算机在每天工作结束时产生一天中游客总的租船次数和总的租船时间的报告。
2) 实体动作步
实体:游客
实体标识符:游客姓名
动作:租船。动作属性:船编号、租用时间(开始时间)
还船。动作属性:船编号。退还时间(结束时间)
输出:租船总次数
总的租船时间T=T+∑还船时间-∑租船时间
3) 实体结构步
实体结构如同9.8所示。
图9.8 实体结构
4) 初始模型步
用系统说明图来描述初始模型如图9.9所示。系统说明图即为顺序进程网络。
图9.9 系统说明图
5) 功能步
游客进程和职员进程的纲要逻辑描述如下:
游客1进程seq
session_time:=0;
read C;
租船seq
session_time:=session_time一租船时间;
租船end
read C;
还船seq
session_time:=session_time+还船时间;
还船end
游客1进程end
职员进程iter
报告seq
read REQ ;
totaltime:=0 ;number:=0;
get CV;
处理租船 iter while(not end_of_CVs)
totaltime:= totaltime+session_time;
number:=number+1;
get CV;
处理租船end
write Reportline(‘总租船次数’,numbrr,‘总租船时间’,totaltime);
报告end
职员进程end
6) 实现步
前面形成的软件系统说明中,游客进程有成千上万个,可能是并发的,这不能在有限的处
理机上运行,因此设置一调度程序,处理多进程的运行调度。
若在计算机中保存所有进程的正文拷贝和运行状态向量,则将占用大量存储空间,因此将正文同其状态向量分离保存。因同一类进程的动作相同,则只保存一个正文拷贝,当某一进程激活时,将该类进程正文同该进程的状态向量重新结合,占用处理机资源,形成一个活动进程。
将上述软件系统说明用系统实现图来实现,如图9.10所示。
图9.IO 系统实现图
四 小 结
本章所讲的内容小结如下:
(1) JSP方法主要体现程序结构的设计,不明确地划分软件概要设计和详细设计的两个阶段。根据JSP的规则直接推出程序结构。可以将它与SD方法相结合,用SD方法设计体系结构,用JSP方法设计它的局部模块。
(2) JSP方法主要用于规模不大的数据处理系统,输入、输出数据结构能较容易地描述出来的情况。对于较大的系统,涉及很多输入、输出数据,其结构又不互相对应的情况,用JSP方法解决要困难一些。
(3) JSD方法开创性地进行了对客观世界及其同软件间关系的研究。JSD方法第一次揭示了某些软件概念(输入数据)同客观世界(用户业务)概念的一种内在联系,指出所谓软件系统的输入数据,实际上是系统所关心的客观世界动态行为的一种计算机所能接受的信息的表述;同时使这部分软件系统概念结构(JSD方法中的模型结构)保持其所内含的客观世界概念的自然结构,因此极大地提高了软件系统结构的正确性、稳固性、可理解性和可维护性。
(4) JSD明确了软件系统说明决策同软件系统实现决策的界限。传统的应用软件开发方法在软件系统说明中只包含软件系统是做什么的说明,而不包含软件系统是怎么做的逻辑说明,这一说明决策是同软件系统的实现决策一起在软件设计和编码阶段才开发的。由于这样形成的软件系统不能构成一完整、可工作的系统,因此造成软件系统理解、移植和实现的困难。事实上两种完全不同的开发决策混杂在一起进行,人为地增加了软件系统开发的复杂性,而JSD方法由于明确划分了软件系统说明决策同软件系统实现决策的界限而克服了以上缺陷。
(5) JSD对客观世界及其同软件间关系的认识不完整。JSD方法并未揭示算法、输出数据同客观世界概念的内在联系。这使得 JSD方法中功能进程的开发仍基于JSP的程序设计技术来进行,开发出的功能进程结构完全是计算机算法性的,它与顺序进程不同,顺序进程是由一系列动作组织成的结构,这也使得JSD方法中输出数据的组织无一定规则,其划分基本上由开发者随意进行,从而软件系统中功能进程的组织也是无章法的。其中顺序进程和功能进程概念和结构上不一致会导致某些应用软件系统开发时的严重困难。
(6) JSD方法未能充分利用新发展的软件概念,致使确立的软件系统实现结构过于复杂,不易为软件开发者接受。
(7) 软件说明结构的描述技术不恰当。软件系统说明的作用在于提供不受具体目标计算机因素影响、供所有开发者使用的标准的软件系统说明。而JSD方法却采用第三代语言等目标机程序设计语言来描述软件系统说明,这不利于软件开发者对系统的理解和他们之间的通信交流,因为大多数软件开发者使用掌握的第三代语言并不相同。同时第三代语言由于比较低级并不适于对系统说明提供最直接有效的支持。
JSD方法的上述这些缺陷在很大程度上限制了人们实际运用JSD方法的热情。