一、概述
软件工程的定义
软件工程就是为了经济地获得可靠的且能在实际机器上有效地运行的软件,而建立和使用完善的工程原理。
软件工程的内容(应该?)
软件工程是指导计算机软件开发和维护的一门工程学科。
采用工程的概念、原理、技术和方法来开发与维护软件,把经过时间考验而证明正确的管理技术和当前能够得到的最好的技术方法结合起来,以经济地开发出高质量的软件并有效地维护它,这就是软件工程。
软件工程的目标
软件工程的目标是经济地开发出高质量的软件
软件工程的特征
- 软件工程关注于大型程序的构造
- 软件工程的中心课题是控制复杂性
- 软件经常变化
- 开发软件的效率非常重要
- 和谐地合作是开发软件的关键
- 软件必须有效地支持它的用户
- 在软件工程领域中是由具有一种文化背景的人替具有另一种文化背景的人创造产品
软件的定义
1983年IEEE为软件下的定义是:计算机程序、方法、规则、相关的文档资料以及在计算机上运行程序时所必需的数据。
软件生存周期
软件生命周期由软件定义、软件开发、运行维护 3个时期组成,每个时期又进一步划分成若干个阶段。
软件定义
软件定义时期的任务是:
- 确定软件开发工程必须完成的总目标;
- 确定工程的可行性;
- 导出实现工程目标应该采用的策略及系统必须完成的功能;
- 估计完成该项工程需要的资源和成本,并且制定工程进度表。
这个时期的工作通常又称为系统分析,由系统分析员负责完成。
软件定义时期通常进一步划分成3个阶段:
- 问题定义
- 可行性研究
- 需求分析
软件开发
开发时期具体设计和实现在前一个时期定义的软件,它通常由下述4个阶段组成:
- 总体设计
- 详细设计
- 编码和单元测试
- 综合测试。
其中前两个阶段又称为系统设计,后两个阶段又称为系统实现。
软件维护
维护时期的主要任务是使软件持久地满足用户的需要。
- 当软件在使用过程中发现错误时应该加以改正;
- 当环境改变时应该修改软件以适应新的环境;
- 当用户有新要求时应该及时改进软件以满足用户的新需要。
通常对维护时期不再进一步划分阶段,但是每一次维护活动本质上都是一次压缩和简化了的定义和开发过程。
模型(瀑布、演化、螺旋、喷泉)
瀑布模型
传统瀑布模型如下
特点
- 阶段间具有顺序性和依赖性
这个特点有两重含义:
①必须等前一阶段的工作完成之后,才能开始后一阶段的工作;
②前一阶段的输出文档就是后一阶段的输入文档。
因此,只有前一阶段的输出文档正确,后一阶段的工作才能获得正确的结果。
- 推迟实现的观点
对于规模较大的软件项目来说,往往编码开始得越早最终完成开发工作所需要的时间反而越长。这是因为,前面阶段的工作没做或做得不扎实,过早地考虑进行程序实现,往往导致大量返工,有时甚至发生无法弥补的问题,带来灾难性后果。
- 质量保证的观点
软件工程的基本目标是优质、高产。为了保证所开发的软件的质量,在瀑布模型的每个阶段都应坚持两个重要做法:
(1)每个阶段都必须完成规定的文档,没有交出合格的文档就是没有完成该阶段的任务。
(2)每个阶段结束前都要对所完成的文档进行评审,以便尽早发现问题,改正错误。
实际上的瀑布模型如下
优点
- 可强迫开发人员采用规范的方法(例如,结构化技术)
- 严格地规定了每个阶段必须提交的文档
- 要求每个阶段交出的所有产品都必须经过质量保证小组的仔细验证。
缺点
- “瀑布模型是由文档驱动的”这个事实也是它的一个主要缺点。
- 在可运行的软件产品交付给用户之前,用户只能通过文档来了解产品是什么样的。
- 总之,由于瀑布模型几乎完全依赖于书面的规格说明,很可能导致最终开发出的软件产品不能真正满足用户的需要。
快速原型模型
所谓快速原型是快速建立起来的可以在计算机上运行的程序,它所能完成的功能往往是最终产品能完成的功能的一个子集。
增量模型
- 把软件产品作为一系列的增量构件来设计、编码、集成和测试。
- 把软件产品分解成增量构件时,应该使构件的规模适中,规模过大或过小都不好。
- 分解时惟一必须遵守的约束条件是,当把新构件集成到现有软件中时,所形成的产品必须是可测试的。
- 增量模型的另一个优点是,逐步增加产品功能可以使用户有较充裕的时间学习和适应新产品,从而减少一个全新的软件可能给客户组织带来的冲击。
- 使用增量模型的困难是,在把每个新的增量构件集成到现有软件体系结构中时,必须不破坏原来已经开发出的产品。
- 软件体系结构必须是开放的。
螺旋模型
基本思想
使用原型及其他方法来尽量降低风险。
优点
- 对可选方案和约束条件的强调有利于已有软件的重用,
- 也有助于把软件质量作为软件开发的一个重要目标
- 减少了过多测试(浪费资金)或测试不足(产品故障多)所带来的风险;
- 更重要的是,在螺旋模型中维护只是模型的另一个周期,在维护和开发之间并没有本质区别。
- 螺旋模型主要适用于内部开发的大规模软件项目。
缺点
- 螺旋模型的主要优势在于,它是风险驱动的,但是,这也可能是它的一个弱点。
- 除非软件开发人员具有丰富的风险评估经验和这方面的专门知识,否则将出现真正的风险:当项目实际上正在走向灾难时,开发人员可能还认为一切正常。
喷泉模型
喷泉模型的优点
喷泉模型不像瀑布模型那样,需要分析活动结束后才开始设计活动,设计活动结束后才开始编码活动。该模型的各个阶段没有明显的界限,开发人员可以同步进行开发。其优点是可以提高软件项目开发效率,节省开发时间,适应于面向对象的软件开发过程。 [1]
喷泉模型的缺点
由于喷泉模型在各个开发阶段是重叠的,因此在开发过程中需要大量的开发人员,因此不利于项目的管理。此外这种模型要求严格管理文档,使得审核的难度加大,尤其是面对可能随时加入各种信息、需求与资料的情况。
CASE
???what’s this???
二、系统定义与软件计划
这个阶段要回答的关键问题是:“对于上一个阶段所确定的问题有行得通的解决办法吗?”
可行性研究的目的
确定问题是否值得去解决
可行性研究的任务
- 可行性研究最根本的任务是对以后的行动方针提出建议。
- 首先需要分析和澄清问题定义
- 在澄清了问题定义之后,分析员应该导出系统的逻辑模型。然后从系统逻辑模型出发,探索若干种可供选择的主要解法(即系统实现方案)。对每种解法都应该仔细研究它的可行性。
可行性研究的三个方面
- 技术可行性使用现有的技术能实现这个系统吗?
- 经济可行性这个系统的经济效益能超过它的开发成本吗?
- 操作可行性系统的操作方式在这个用户组织内行得通吗?
必要时还要从法律、社会效益等更广泛的方面研究每种解法的可行性
可行性研究过程
- 复查系统规模和目标
- 研究目前正在使用的系统
- 导出新系统的高层逻辑模型
- 进一步定义问题
- 导出和评价供选择的解法
- 推荐行动方针
- 草拟开发计划
- 书写文档提交审查
系统流程图
基本思想是用图形符号以黑盒子形式描绘组成系统的每个部件(程序,文档,数据库,人工过程等)。系统流程图表达的是数据在系统各部件之间流动的情况,而不是对数据进行加工处理的控制过程。它是物理数据流图而不是程序流程图。
数据流图
- 数据流图(DFD)是一种图形化技术,它描绘信息流和数据从输入移动到输出的过程中所经受的变换。
- 在数据流图中没有任何具体的物理部件,它只是描绘数据在软件中流动和被处理的逻辑过程。
- 数据流图是系统逻辑功能的图形表示
- 设计数据流图时只需考虑系统必须完成的基本逻辑功能
符号
示例
系统级
一层数据流图
二层数据流图
命名规则
- 为数据流(或数据存储)命名
(1) 名字应代表整个数据流(或数据存储)的内容,而不是仅仅反映它的某些成分。
(2) 不要使用空洞的、缺乏具体含义的名字(如“数据”、“信息”、“输入”之类)。
(3) 如果在为某个数据流(或数据存储)起名字时遇到了困难,则很可能是因为对数据流图分解不恰当造成的,应该试试重新分解,看是否能克服这个困难。
- 为处理命名
(1) 通常先为数据流命名,然后再为与之相关联的处理命名。这样命名比较容易,而且体现了人类习惯的“由表及里”的思考过程。
(2)名字应该反映整个处理的功能,而不是它的一部分功能。
(3)名字最好由一个具体的及物动词加上一个具体的宾语组成。应该尽量避免使用“加工”、“处理”等空洞笼统的动词作名字。
(4)通常名字中仅包括一个动词,如果必须用两个动词才能描述整个处理的功能,则把这个处理再分解成两个处理可能更恰当些。
(5)如果在为某个处理命名时遇到困难,则很可能是发现了分解不当的迹象,应考虑重新分解。
(6)数据源点/终点是目标系统的外围环境部分,采用它们在问题域中习惯使用的名字。
用途
- 画数据流图的基本目的是利用它作为交流信息的工具。
- 数据流图应该分层,并且在把功能级数据流图细化后得到的处理超过9个时,应该采用画分图的办法,也就是把每个主要功能都细化为一张数据流分图,而原有的功能级数据流图用来描绘系统的整体逻辑概貌。
- 数据流图的另一个主要用途是作为分析和设计的工具。
三、需求分析
这个阶段的任务是准确地确定“为了解决这个问题,目标系统必须做什么”,主要是确定目标系统必须具备哪些功能。
需求分析的任务
- 确定对系统的综合要求
- 功能需求
指定系统必须提供的服务。需求分析应该划分出系统必须完成的所有功能。- 性能需求
性能需求指定系统必须满足的定时约束或容量约束,通常包括速度(响应时间)、信息量速率、主存容量、磁盘容量、安全性等方面的需求。- 可靠性和可用性需求
可靠性需求定量地指定系统的可靠性。
可用性与可靠性密切相关,它量化了用户可以使用系统的程度。- 出错处理需求
说明系统对环境错误应该怎样响应。- 接口需求
接口需求描述应用系统与它的环境通信的格式。常见的接口需求有:用户接口需求;硬件接口需求;软件接口需求;通信接口需求。- 约束
设计约束或实现约束描述在设计或实现应用系统时应遵守的限制条件。
常见的约束有:精度;工具和语言约束;设计约束;应该使用的标准;应该使用的硬件平台。- 逆向需求
逆向需求说明软件系统不应该做什么。- 将来可能提出的要求
应该明确地列出那些虽然不属于当前系统开发范畴,但是据分析将来很可能会提出来的要求。
- 分析系统的数据要求
- 任何一个软件系统本质上都是信息处理系统
- 分析系统的数据要求通常采用建立数据模型的方法
- 复杂的数据由许多基本的数据元素组成,数据结构表示数据元素之间的逻辑关系。
- 利用图形工具辅助描绘数据结构,常用的图形工具有层次方框图和Warnier图
- 数据结构规范化
- 导出系统的逻辑模型
综合上述两项分析的结果可以导出系统的详细的逻辑模型,通常用数据流图、实体-联系图、状态转换图、数据字典和主要的处理算法描述这个逻辑模型。
- 修正系统开发计划
根据在分析过程中获得的对系统的更深入更具体的了解,可以比较准确地估计系统的成本和进度,修正以前制定的开发计划。
需求分析是软件生存周期中计划阶段的最后一个步骤
结构化分析方法(SA)
DFD(分层数据流图):概念
分层:
面对复杂的系统时,一个比较好的方法是分层次地描绘这个系统。
首先用一张高层次的系统流程图描绘系统总体概貌,表明系统的关键功能。
然后分别把每个关键功能扩展到适当的详细程度,画在单独的一页纸上。
数据字典(DD)
加工说明:结构化语言、判定表、判定树
与用户沟通获取需求的方法
访谈
- 正式访谈时,系统分析员将提出一些事先准备好的具体问题。
- 在非正式访谈中,分析员将提出一些用户可以自由回答的开放性问题,以鼓励被访问人员说出自己的想法。
- 当需要调查大量人员的意见时,向被调查人分发调查表是一个十分有效的做法。分析员仔细阅读收回的调查表,然后再有针对性地访问一些用户,以便向他们询问在分析调查表时发现的新问题。
- 在访问用户的过程中使用情景分析技术往往非常有效。所谓情景分析就是对用户将来使用目标系统解决某个具体问题的方法和结果进行分析。
面向数据流自顶向下求精
- 软件系统本质上是信息处理系统,而任何信息处理系统的基本功能都是把输入数据转变成需要的输出信息。数据决定了需要的处理和算法。
- 结构化分析方法就是面向数据流自顶向下逐步求精进行需求分析的方法。通过可行性研究已经得出了目标系统的高层数据流图,需求分析的目标之一就是把数据流和数据存储定义到元素级。
- 必须请用户对上述分析过程中得出的结果仔细地复查,数据流图是帮助复查的极好工具。
从输入端开始,分析员借助数据流图、数据字典和IPO图向用户解释输入数据是怎样一步一步地转变成输出数据的。 - 反复进行上述分析过程,分析员越来越深入地定义了系统中的数据和系统应该完成的功能。为了追踪更详细的数据流,分析员应该把数据流图扩展到更低的层次。通过功能分解可以完成数据流图的细化。
- 随着分析过程的进展,经过问题和解答的反复循环,分析员越来越深入具体地定义了目标系统,最终得到对系统数据和功能要求的满意了解。图3.1粗略地概括了上述分析过程。
简易的应用规格说明技术
- 使用传统的访谈或面向数据流自顶向下求精方法定义需求时,用户处于被动地位而且往往有意无意地与开发者区分“彼此”。
- 简易的应用规格说明技术提倡用户与开发者密切合作,共同标识问题,提出解决方案要素,商讨不同方案并指定基本需求。
- 今天,简易的应用规格说明技术已经成为信息系统领域使用的主流技术。
快速建立软件原型
- 快速建立软件原型是最准确、最有效、最强大的需求分析技术。
- 快速原型就是快速建立起来的旨在演示目标系统主要功能的可运行的程序。
- 构建原型的要点是,它应该实现用户看得见的功能(例如,屏幕显示或打印报表),省略目标系统的“隐含”功能(例如,修改文件)。
- 快速原型应该具备的第一个特性是“快速”。
- 快速原型应该具备的第二个特性是“容易修改”。
- 在实际开发软件产品时,原型的“修改—试用—反馈”过程可能重复多遍
需求分析工具
实体-联系图(ER图)
概念性数据模型是一种面向问题的数据模型,是按照用户的观点对数据建立的模型。
它描述了从用户角度看到的数据,它反映了用户的现实环境,而且与在软件系统中的实现方法无关。
内容
- 数据对象
数据对象是对软件必须理解的复合信息的抽象。 所谓复合信息是指具有一系列不同性质或属性的事物,仅有单个值的事物(例如,宽度)不是数据对象。
数据对象可以是外部实体(例如,产生或使用信息的任何事物)、事物(例如,报表)、行为(例如,打电话)、事件(例如,响警报)、角色(例如,教师、学生)、单位(例如,会计科)、地点(例如,仓库)或结构(例如,文件)等。
总之,可以由一组属性来定义的实体都可以被认为是数据对象。 数据对象彼此间是有关联的 数据对象只封装了数据而没有对施加于数据上的操作的引用
- 数据对象的属性
属性定义了数据对象的性质。
必须把一个或多个属性定义为“标识符”
应该根据对所要解决的问题的理解,来确定特定数据对象的一组合适的属性。
- 数据对象彼此间相互连接的关系(联系)
联系可分为以下3种类型:
(1) 一对一联系(1∶1)
(2) 一对多联系(1∶N)
(3)多对多联系(N:N)
示例
符号
- 矩形框代表实体
- 用连接相关实体的菱形框表示关系
- 用椭圆形或圆角矩形表示实体(或关系)的属性
- 用直线把实体(或关系)与其属性连接起来。
状态转换图
状态转换图(简称为状态图)通过描绘系统的状态及引起系统状态转换的事件,来表示系统的行为。
状态图还指明了作为特定事件的结果系统将做哪些动作(例如,处理数据)。
状态图提供了行为建模机制,可以满足第3条分析准则的要求。
内容
- 状态
- 状态是任何可以被观察到的系统行为模式,一个状态代表系统的一种行为模式。
- 状态规定了系统对事件的响应方式。
系统对事件的响应,既可以是做一个(或一系列)动作,也可以是仅仅改变系统本身的状态,还可以是既改变状态又做动作。- 在状态图中定义的状态主要有:初态(即初始状态)、终态(即最终状态)和中间状态。在一张状态图中只能有一个初态,而终态则可以有0至多个。
- 状态图既可以表示系统循环运行过程,也可以表示系统单程生命期。当描绘循环运行过程时,通常并不关心循环是怎样启动的。当描绘单程生命期时,需要标明初始状态(系统启动时进入初始状态)和最终状态(系统运行结束时到达最终状态)。
- 事件
事件是在某个特定时刻发生的事情,它是对引起系统做动作或(和)从一个状态转换到另一个状态的外界事件的抽象。
- 符号表示
- 在状态图中,初态用实心圆表示,终态用一对同心圆(内圆为实心圆)表示。
- 中间状态用圆角矩形表示,可以用两条水平横线把它分成上、中、下3个部分。上面部分为状态的名称,这部分是必须有的;中间部分为状态变量的名字和值,这部分是可选的;下面部分是活动表,这部分也是可选的。
- 活动表的语法格式如下:事件名(参数表)/动作表达式
示例
层次方框图
- 层次方框图用树形结构的一系列多层次的矩形框描绘数据的层次结构。树形结构的顶层是一个单独的矩形框,它代表完整的数据结构,下面的各层矩形框代表这个数据的子集,最底层的各个框代表组成这个数据的实际数据元素(不能再分割的元素)。
- 随着结构的精细化,层次方框图对数据结构也描绘得越来越详细,这种模式非常适合于需求分析阶段的需要。
- 系统分析员从对顶层信息的分类开始,沿图中每条路径反复细化,直到确定了数据结构的全部细节时为止。
Warnier图
- 和层次方框图类似,Warnier图也用树形结构描绘信息,但是这种图形工具比层次方框图提供了更丰富的描绘手段。
- 用Warnier图可以表明信息的逻辑组织。
IPO图
- IPO图是输入、处理、输出图的简称
- 能够方便地描绘输入数据、对数据的处理和输出数据之间的关系
- IPO图使用的基本符号既少又简单
- 它的基本形式是在左边的框中列出有关的输入数据,在中间的框内列出主要的处理,在右边的框内列出产生的输出数据。
- 处理框中列出处理的次序暗示了执行的顺序,但是用这些基本符号还不足以精确描述执行处理的详细情况。
- 在IPO图中还用类似向量符号的粗大箭头清楚地指出数据通信的情况。
改进的IPO图(也称为IPO表),这种图中包含某些附加的信息,在软件设计过程中将比原始的IPO图更有用。
软件工具应该满足下列要求:
(1) 必须有形式化的语法(或表),因此可以用计算机自动处理使用这种语法说明的内容;
(2) 使用这个软件工具能够导出详细的文档;
(3) 必须提供分析(测试)规格说明书的不一致性和冗余性的手段,并且应该能够产生一组报告指明对完整性分析的结果;
(4) 使用这个软件工具之后,应该能够改进通信状况。
软件需求说明书(SRS)
- 通过需求分析除了创建分析模型之外,还应该写出软件需求规格说明书,它是需求分析阶段得出的最主要的文档。
- 内容:通常用自然语言完整、准确、具体地描述系统的数据要求、功能需求、性能需求、可靠性和可用性要求、出错处理需求、接口需求、约束、逆向需求以及将来可能提出的要求。
- 为了消除用自然语言书写的软件需求规格说明书中可能存在的不一致、歧义、含糊、不完整及抽象层次混乱等问题,有些人主张用形式化方法描述用户对软件系统的需求。
四、概要设计(总体设计)
总体设计的基本
概要设计设计的基本任务
- 总体设计的基本目的就是回答“概括地说,系统应该如何实现?”这个问题,总体设计又称为概要设计或初步设计。
- 总体设计需要划分出组成系统的物理元素——程序、文件、数据库、人工过程和文档等等,但是每个物理元素仍然处于黑盒子级。
- 总体设计的另外一项重要任务是设计软件的结构,也就是要确定系统中每个程序是由哪些模块组成的,以及这些模块相互间的关系。
概要设计设计的基本方法
- 总体设计过程首先寻找实现目标系统的各种不同的方案,需求分析阶段得到的数据流图是设想各种可能方案的基础。
- 然后分析员从这些供选择的方案中选取若干个合理的方案,为每个合理的方案都准备一份系统流程图,列出组成系统的所有物理元素,进行成本/效益分析,并且制定实现这个方案的进度计划。
- 分析员应该综合分析比较这些合理的方案,从中选出一个最佳方案向用户和使用部门负责人推荐。
总体设计的必要性
可以站在全局高度上,花较少成本,从较抽象的层次上分析对比多种可能的系统实现方案和软件结构,从中选出最佳方案和最合理的软件结构,从而用较低成本开发出较高质量的软件系统。
总体设计的设计过程
总体设计过程通常由两个主要阶段组成:
- 系统设计阶段,确定系统的具体实现方案;
- 结构设计阶段,确定软件结构。
典型的总体设计过程包括下述9个步骤:
- 设想供选择的方案
- 选取合理的方案
- 推荐最佳方案
- 功能分解
- 设计软件结构
- 设计数据库
- 制定测试计划
- 书写文档
- 审查和复审
模块划分的原则:高内聚、低耦合
模块化
模块是由边界元素限定的相邻程序元素(例如,数据说明,可执行的语句)的序列,而且有一个总体标识符代表它。按照模块的定义,过程、函数、子程序和宏等,都可作为模块。面向对象方法学中的对象是模块,对象内的方法(或称为服务)也是模块。模块是构成程序的基本构件。
模块独立
- 模块独立的概念是模块化、抽象、信息隐藏和局部化概念的直接结果。
- 开发具有独立功能而且和其他模块之间没有过多的相互作用的模块,就可以做到模块独立。换句话说,希望这样设计软件结构,使得每个模块完成一个相对独立的特定子功能,并且和其他模块之间的关系很简单
模块独立性的重要性
- 第一,有效的模块化(即具有独立的模块)的软件比较容易开发出来。这是由于能够分割功能而且接口可以简化,当许多人分工合作开发同一个软件时,这个优点尤其重要。
- 第二,独立的模块比较容易测试和维护。这是因为相对说来,修改设计和程序需要的工作量比较小,错误传播范围小,需要扩充功能时能够“插入”模块。总之,模块独立是好设计的关键,而设计又是决定软件质量的关键环节。
模块的独立程度的度量:内聚和耦合
耦合
耦合是对一个软件结构内不同模块之间互连程度的度量。耦合强弱取决于模块间接口的复杂程度,进入或访问一个模块的点,以及通过接口的数据。
- 数据耦合 :两个模块之间的通讯信息是若干个数据
由于两者之间没有控制信号的交换,因此相互间的影响最小,模块间没有直接关系,完全靠上级模块调用或控制,如报表生成模块和打印模块 - 控制耦合 :两个模块之间传递的信息中含有控制信号,使得一个模块控制了另一个模块的内部逻辑
- 公共耦合:两个模块通过对全局公共数据区的访问建立联系
因为若干个模块共用某几个数据,就使联结关系复杂起来,增加了模块修改的难度 - 内容耦合:一个模块不经调用直接使用另一模块的内容
例如模块A用绝对地址直接使用模块B的数据就是一例。这是最坏的一种联结形式,给模块维护带来很大困难
内聚
内聚标志一个模块内各个元素彼此结合的紧密程度,它是信息隐藏和局部化概念的自然扩展。简单地说,理想内聚的模块只做一件事情。
设计时应该力求做到高内聚,通常中等程度的内聚也是可以采用的,而且效果和高内聚相差不多;但是,低内聚很坏,不要使用。
- 偶然内聚:模块内各成分间无实质性联系,只是偶然地被凑合到一起,如把一些函数写在同一个源文件里
- 逻辑内聚:将几个逻辑上相似 (实际上并无必然联系) 的功能放入一个模块,在调用时由传递参数决定执行哪种功能,如把错误信息的处理集中在一起
- 时间内聚:将若干在同一个时间带内进行的工作集中在一起所形成的模块,但这些工作彼此间毫无关系,如初始化模块 要对所有变量赋初值,对所有介质上的文件置初值等
- 过程内聚:模块内的各成分是相关的,且必须以特定的次序执行,中间不能穿插其他工作,如果把流程图中某一部分划分出来组成模块,就会形成过程内聚模块。例如,将流程图中的循环、判定和计算分成三个模块,则均为过程内聚模块
- 通讯内聚:模块中的各成分引用相同输入数据和 (或) 产生相同的输出数据,但各成分的执行次序可以是任意的,如若干个处理同一数据文件的功能
- 顺序内聚:模块内各成分间具有这样的特征:前一成分所产生的输出是另一成分的输入,如在同一数据结构上操作的各种功能,强调数据的顺序;而过程内聚强调的是加工处理的先后。
- 功能内聚:模块内所有成分属于一个整体,为完成同一个功能而存在,解一个方程;计算利息等。这种内聚方式的优点是,模块容易修改和维护,故内聚度最高
高内聚和低耦合
- 内聚和耦合是密切相关的,模块内的高内聚往往意味着模块间的低耦合
- 内聚度和耦合度要说明的是同一内容,即模块的独立性,它们是衡量这种独立性的两个不同的方面
结构化设计方法(SD):适用范围、总体思想
结构化设计方法是基于模块化、自顶向下细化、结构化程序设计等程序设计技术基础发展起来的。
基本思想
将软件设计成由相对独立且具有单一功能的模块组成的结构,分为概要设计和详细设计两个阶段。
模块结构图(SC):显示模块间的调用关系
- 图中一个方框代表一个模块,框内注明模块的名字或主要功能;
- 方框之间的箭头(或直线)表示模块的调用关系。因为按照惯例总是图中位于上方的方框代表的模块调用下方的模块,即使不用箭头也不会产生二义性。
- 为了简单起见,可以只用直线而不用箭头表示模块间的调用关系。
ER图与数据库设计
概要设计说明书
五、详细设计
详细设计阶段的任务就是把解法具体化,也就是回答下面这个关键问题:“应该怎样具体地实现这个系统呢?”
目标
详细设计阶段的根本目标是确定应该怎样具体地实现所要求的系统,也就是说,经过这个阶段的设计工作,应该得出对目标系统的精确描述,从而在编码阶段可以把这个描述直接翻译成用某种程序设计语言书写的程序。
任务:模块内的算法描述
详细设计阶段的任务还不是具体地编写程序,而是要设计出程序的“蓝图”,以后程序员将根据这个蓝图写出实际的程序代码。因此,详细设计的结果基本上决定了最终的程序代码的质量。考虑程序代码的质量时必须注意,程序的“读者”有两个,那就是计算机和人。
详细设计工具:
程序流程图、NS图(方块图)、HIPO图、PAD图(问题分析图)
程序流程图
概述
程序流程图又称为程序框图,它是历史最悠久、使用最广泛的描述过程设计的方法,然而它也是用得最混乱的一种方法。
分支
缺点
- 程序流程图本质上不是逐步求精的好工具,它诱使程序员过早地考虑程序的控制流程,而不去考虑程序的全局结构。
- 程序流程图中用箭头代表控制流,因此程序员不受任何约束,可以完全不顾结构程序设计的精神,随意转移控制。
- 程序流程图不易表示数据结构。
盒图(NS图)
出于要有一种不允许违背结构程序设计精神的图形工具的考虑,Nassi和Shneiderman提出了盒图,又称为N-S图。
特点
- 功能域(即,一个特定控制结构的作用域)明确,可以从盒图上一眼就看出来。
- 不可能任意转移控制。
- 很容易确定局部和全程数据的作用域。
- 很容易表现嵌套关系,也可以表示模块的层次结构。
符号
示例
层次图
层次图用来描绘软件的层次结构。层次图中的一个矩形框代表一个模块,方框间的连线表示调用关系而不像层次方框图那样表示组成关系。
层次图很适于在自顶向下设计软件的过程中使用。
HIPO图
HIPO图具有可追踪性,在H图(层次图)里除了最顶层的方框之外,每个方框都加了编号
PAD图
PAD是问题分析图(problem analysis diagram)的英文缩写,自1973年由日本日立公司发明以后,已得到一定程度的推广。它用二维树形结构的图来表示程序的控制流,将这种图翻译成程序代码比较容易。
优点
- 使用表示结构化控制结构的PAD符号所设计出来的程序必然是结构化程序。
- PAD图所描绘的程序结构十分清晰。图中最左面的竖线是程序的主线,即第一层结构。随着程序层次的增加,PAD图逐渐向右延伸,每增加一个层次,图形向右扩展一条竖线。PAD图中竖线的总条数就是程序的层次数。
- 用PAD图表现程序逻辑,易读、易懂、易记。PAD图是二维树形结构的图形,程序从图中最左竖线上端的结点开始执行,自上而下,从左向右顺序执行,遍历所有结点。
- 容易将PAD图转换成高级语言源程序,这种转换可用软件工具自动完成,从而可省去人工编码的工作,有利于提高软件可靠性和软件生产率。
- 即可用于表示程序逻辑,也可用于描绘数据结构。
- PAD图的符号支持自顶向下、逐步求精方法的使用。开始时设计者可以定义一个抽象的程序,随着设计工作的深入而使用def符号逐步增加细节,直至完成详细设计。
PAD图是面向高级程序设计语言的,为FORTRAN,COBOL和PASCAL等每种常用的高级程序设计语言都提供了一整套相应的图形符号。由于每种控制语句都有一个图形符号与之对应,显然将PAD图转换成与之对应的高级语言程序比较容易。
符号
示例
判定树
判定表虽然能清晰地表示复杂的条件组合与应做的动作之间的对应关系,但其含义却不是一眼就能看出来的,初次接触这种工具的人理解它需要有一个简短的学习过程。此外,当数据元素的值多于两个时,判定表的简洁程度也将下降。
过程设计语言PDL
过程设计语言(PDL)也称为伪码,这是一个笼统的名称,现在有许多种不同的过程设计语言在使用。它是用正文形式表示数据和处理过程的设计工具。
PDL具有严格的关键字外部语法,用于定义控制结构和数据结构;另一方面,PDL表示实际操作和条件的内部语法通常又是灵活自由的,可以适应各种工程项目的需要。因此,一般说来,PDL是一种“混杂”语言,它使用一种语言的词汇,同时却使用另一种语言(某种结构化的程序设计语言)的语法。
特点
- 关键字的固定语法,它提供了结构化控制结构、数据说明和模块化的特点。为了使结构清晰和可读性好,通常在所有可能嵌套使用的控制结构的头和尾都有关键字,例如,if…fi(或endif)等等。
- 自然语言的自由语法,它描述处理特点。
- 数据说明的手段。应该既包括简单的数据结构(例如纯量和数组),又包括复杂的数据结构(例如,链表或层次的数据结构)。
- 模块定义和调用的技术,应该提供各种接口描述模式。
优点
- 可以作为注释直接插在源程序中间。这样做能促使维护人员在修改程序代码的同时也相应地修改PDL注释,因此有助于保持文档和程序的一致性,提高了文档的质量。
- 可以使用普通的正文编辑程序或文字处理系统,很方便地完成PDL的书写和编辑工作。
- 已经有自动处理程序存在,而且可以自动由PDL生成程序代码。
缺点
不如图形工具形象直观,描述复杂的条件组合与动作间的对应关系时,不如判定表清晰简单。
示例(拼写检查)
PROCEDURE spellcheck IS
BEGIN
split document into single words
load up words in dictionary
display words which are not in dictionary
create a new dictionary
END spellcheck
详细设计说明书
详细设计产生的主要文件是详细设计说明书,它为编写源代码提供了必要的说明
六、软件编码
这个阶段的关键任务是写出正确的容易理解、容易维护的程序模块。
程序员应该根据目标系统的性质和实际环境,选取一种适当的高级程序设计语言(必要时用汇编语言),把详细设计的结果翻译成用选定的语言书写的程序,并且仔细测试编写出的每一个模块。
结构化程序设计(SP):概念
结构化程序设计(structured programming)是进行以模块功能和处理过程设计为主的详细设计的基本原则。结构化程序设计是过程式程序设计的一个子集,它对写入的程序使用逻辑结构,使得理解和修改更有效更容易。
程序设计风格
源程序代码的逻辑简明清晰、易读易懂是好程序的一个重要标准,为了做到这一点,应该遵循下述规则。
- 程序内部的文档
- 数据说明
- 语句构造
- 输入输出
- 效率
程序内部的文档
程序清单的布局对于程序的可读性也有很大影响,应该利用适当的阶梯形式使程序的层次结构清晰明显。编写源程序文件通常要考虑的问题包括
- 符号名的命名
- 程序中的注释
- 序言性注释
- 功能性注释
- 空行和缩格等
数据说明
- 从便于阅读、便于维护的要求考虑,最好使数据说明规范化。例如,规定说明次序为
- 简单变量说明
- 公用数据块说明
- 数组说明
- 文件说明
- 在文件说明中,多个符号名最好按字母顺序排列
- 如果设计了一个复杂的数据结构,应当使用注释来说明在程序实现时这个数据结构的固有特点
语句构造
程序的清晰性是最重要的目标
- 不要为了节省空间而把多个语句写在同一行
- 程序编写首先考虑清晰性,不要刻意追求技巧性
- 一般情况下,首先保证程序正确,然后才要求提高速度
- 尽量避免复杂的条件测试
- 尽可能使用库函数
- 尽量只采用3种基本的控制结构来编写程序
- 尽量减少对 “非”条件的测试
- 避免大量使用循环嵌套和条件嵌套
- 利用括号使表达式的运算次序清晰直观
输入输出
在设计和编写程序时应该考虑下述有关输入输出风格的规则:
- 对所有输入数据都进行检验;
- 检查输入项重要组合的合法性;
- 保持输入格式简单;
- 使用数据结束标记,
- 不要要求用户指定数据的数目;
- 明确提示交互式输入的请求,详细说明可用的选择或边界数值;
- 当程序设计语言对格式有严格要求时,应保持输入格式一致;
- 设计良好的输出报表;
- 给所有输出数据加标志
效率
程序运行时间效率
- 写程序之前先简化算术的和逻辑的表达式
- 仔细研究嵌套的循环,以确定是否有语句可以从内层往外移
- 尽量避免使用多维数组
- 尽量避免使用指针和复杂的标
- 使用执行时间短的算术运算
- 不要混和使用不同的数据类型
- 尽量使用整数运算和布尔表达式
主要考虑以下三个因素
(1) 程序运行时间
(2) 存储器效率
(3) 输入输出的效率
七、软件测试
这个阶段的关键任务是通过各种类型的测试(及相应的调试)使软件达到预定的要求。
软件测试的目的
G.Myers给出了关于测试的一些规则,这些规则也可以看作是测试的目标或定义。
- 测试是为了发现程序中的错误而执行程序的过程;
- 好的测试方案是极可能发现迄今为止尚未发现的错误的测试方案;
- 成功的测试是发现了至今为止尚未发现的错误的测试。
软件测试的阶段及各阶段与什么文档有关
测试步骤
- 模块测试(单元测试)
在设计得好的软件系统中,每个模块完成一个清晰定义的子功能,而且这个子功能和同级其他模块的功能之间没有相互依赖关系。因此,有可能把每个模块作为一个单独的实体来测试,而且通常比较容易设计检验模块正确性的测试方案。模块测试的目的是保证每个模块作为一个单元能正确运行,所以模块测试通常又称为单元测试。在这个测试步骤中所发现的往往是编码和详细设计的错误。
- 子系统测试
子系统测试是把经过单元测试的模块放在一起形成一个子系统来测试。模块相互间的协调和通信是这个测试过程中的主要问题,因此,这个步骤着重测试模块的接口。
- 系统测试
系统测试是把经过测试的子系统装配成一个完整的系统来测试。在这个过程中不仅应该发现设计和编码的错误,还应该验证系统确实能提供需求说明书中指定的功能,而且系统的动态特性也符合预定要求。在这个测试步骤中发现的往往是软件设计中的错误,也可能发现需求说明中的错误。
不论是子系统测试还是系统测试,都兼有检测和组装两重含义,通常称为集成测试。
- 验收测试(确认测试)
验收测试把软件系统作为单一的实体进行测试,测试内容与系统测试基本类似,但是它是在用户积极参与下进行的,而且可能主要使用实际数据(系统将来要处理的信息)进行测试。验收测试的目的是验证系统确实能够满足用户的需要,在这个测试步骤中发现的往往是系统需求说明书中的错误。验收测试也称为确认测试。
- 平行运行
关系重大的软件产品在验收之后往往并不立即投入生产性运行,而是要再经过一段平行运行时间的考验。所谓平行运行就是同时运行新开发出来的系统和将被它取代的旧系统,以便比较新旧两个系统的处理结果。这样做的具体目的有如下几点:
(1) 可以在准生产环境中运行新系统而又不冒风险;
(2) 用户能有一段熟悉新系统的时间;
(3) 可以验证用户指南和使用手册之类的文档;
(4) 能够以准生产模式对新系统进行全负荷测试,可以用测试结果验证性能指标。
白盒法:概念、不同覆盖率
概念
白盒测试法与黑盒测试法相反,它的前提是可以把程序看成装在一个透明的白盒子里,测试者完全知道程序的结构和处理算法。这种方法按照程序内部的逻辑测试程序,检测程序中的主要执行通路是否都能按预定要求正确工作。白盒测试又称为结构测试。
设计测试方案是测试阶段的关键技术问题。
测试方案包括具体的测试目的(例如,预定要测试的具体功能),应该输入的测试数据和预期的结果。通常又把测试数据和预期的输出结果称为测试用例。其中最困难的问题是设计测试用的输入数据。
不同的测试数据发现程序错误的能力差别很大,为了提高测试效率降低测试成本,应该选用高效的测试数据。因为不可能进行穷尽的测试,选用少量“最有效的”测试数据,做到尽可能完备的测试就更重要了。
逻辑覆盖
有选择地执行程序中某些最有代表性的通路是对穷尽测试的惟一可行的替代办法。所谓逻辑覆盖是对一系列测试过程的总称,这组测试过程逐渐进行越来越完整的通路测试。测试数据执行(或叫覆盖)程序逻辑的程度可以划分成哪些不同的等级呢?
从覆盖源程序语句的详尽程度分析。
例如
4个可能的路径以及应该满足的表达式
L1(a->c->e):M and N
L2(a->b->d):~M and ~N
L3(a->b->e):~M and N
L4(a->c->d):M and ~N
其中
M = {(A>1) and (B=0)};
N = {(A=2) or (X/A>1)}
语句覆盖
语句覆盖:就是指设计若干个测试用例,使得用这些测试用例执行测试之后使得每一条可执行语句至少被执行一遍。
对于前面的例子,L1包含了所有的可执行语句,所以根据L1来设计测试用例就可以达到100%语句覆盖。
用例如下:
{input(A,B,x); output(A,B,x)}={(2,0,4), (2,0,3)}
不足
- 语句覆盖可以保证检验了每一个可执行语句。
- 但是不能保证用于控制的逻辑运算得到充分的检验。
- 比如第一个逻辑运算中的and错写成了or,最后的结果仍然成立。
if (A>1) and (B=0)
x=x/A;
if (A=2) or (X>1)
x=x+1;
- 语句覆盖是最弱的逻辑覆盖。
判定覆盖
又称为分支覆盖:设计若干个测试用例,执行测试,使得被测单元中的每个判定的取值TRUE和FALSE分支至少经历一次。
对于判定(A>1) and (B=0)和(A=2) or (X>0)分别测试其true, false分支。可以选择L1,L2组合或者L3,L4组合。
对于L1,L2组合,L1: {(2,0,4),(2,0,3)} L2:{(1,1,1), (1,1,1)};
对于L3,L4组合,L1: {(2,1,1),(2,1,2)} L2: {(3,0,3), (3,1,1)};
不足
- 复合判定中,某个子判定的错误不一定引起整个判定的值的改变。这样的错误可能被漏掉。
- 比如:使用上面定义的测试的时候,如果第二个判定中X>1成为了X<1,最后的结果还是一样的。两组测试用例都不能测试这些值。
- 弥补这个缺陷的是条件覆盖。
条件覆盖
设计若干个用例,执行测试,每个语句至少执行一次,并且使得程序中每个判定的每个条件的可能取值至少执行一次。
示例
if (A>1) and (B=0)
x=x/A;
if (A=2) or (X>0)
x=x+1;
条件包括:
A>1: T1 not A>1: F1
B=0: T2 not B=0: F2
A=2: T3 not A=2: F3
x>1: T4 not x>1: F4
下面的两组测试用例都满足条件覆盖要求:
不足
- 虽然可以保证每个条件都取不同的值,但是不能保证每个判定都取不同的值。
- 有时甚至不能满足分支覆盖的要求。比如前面的第一组用例。
使用判定-条件覆盖来弥补这个不足。
判定-条件覆盖
判定-条件覆盖就是设计足够的测试用例,使得判定中每个条件的所有可能取值至少执行一次,同时每个判定的所有可能判定结果至少执行一次。
示例
不足
- 某些条件的值错误的时候,判定的值依旧可能是正确的。此时,有关这个条件的错误可能没有被发现。
- (A>1) AND (B=0),如果第一个条件不成立,那么不管第二个条件是否成立,结果都是False。
- 在这样的情况下,条件B=0就没有被检查。
- 因此,即使使用了判定-条件覆盖准则,逻辑表达式中的错误仍然不能表达出来。
条件组合覆盖
条件组合覆盖就是设计测试用例,使得每个判定的条件组合至少执行一次。
对于判定(A>1) and (B=0),其条件组合如下:
对于判定(A=2) or (x>1),也可以得到他的组合。
示例
用例中,没有覆盖路径。
路径覆盖
路径覆盖就是设计足够的测试用例,覆盖程序中所有可能的路径。
不足
- 没有全部覆盖判定的条件组合。
- 对于实际的程序来说,路径覆盖的要求难以达到。当程序包含有循环的时候,其路径理论上是无穷的。
示例
点覆盖
图论中点覆盖的概念定义如下:如果连通图G的子图G′是连通的,而且包含G的所有结点,则称G′是G的点覆盖。
由于流图的每个结点与一条或多条语句相对应,显然,点覆盖标准和语句覆盖标准是相同的。
边覆盖
图论中边覆盖的定义是:如果连通图G的子图G″是连通的,而且包含G的所有边,则称G″是G的边覆盖。为了满足边覆盖的测试标准,要求选取足够多测试数据,使得程序执行路径至少经过流图中每条边一次。通常边覆盖和判定覆盖是一致的。
黑盒法:概念、测试用例设计方法:等价划分、边界值分析
概念
黑盒测试法把程序看作一个黑盒子,完全不考虑程序的内部结构和处理过程。也就是说,黑盒测试是在程序接口进行的测试,它只检查程序功能是否能按照规格说明书的规定正常使用,程序是否能适当地接收输入数据并产生正确的输出信息,程序运行过程中能否保持外部信息的完整性。黑盒测试又称为功能测试。
黑盒测试着重测试软件功能。
黑盒测试并不能取代白盒测试,它是与白盒测试互补的测试方法,它很可能发现白盒测试不易发现的其他类型的错误。
黑盒测试力图发现下述类型的错误:
①功能不正确或遗漏了功能;
②界面错误;
③数据结构错误或外部数据库访问错误;
④性能错误;
⑤初始化和终止错误。
白盒测试在测试过程的早期阶段进行,而黑盒测试主要用于测试过程的后期。
测试用例设计方法
设计黑盒测试方案时,应该考虑下述问题:
(1) 怎样测试功能的有效性?
(2) 哪些类型的输入可构成好测试用例?
(3) 系统是否对特定的输入值特别敏感?
(4) 怎样划定数据类的边界?
(5) 系统能够承受什么样的数据率和数据量?
(6) 数据的特定组合将对系统运行产生什么影响?
应用黑盒测试技术,能够设计出满足下述标准的测试用例集:
(1) 所设计出的测试用例能够减少为达到合理测试所需要设计的测试用例的总数;
(2) 所设计出的测试用例能够告诉我们,是否存在某些类型的错误,而不是仅仅指出与特定测试相关的错误是否存在。
等价划分
等价划分是一种黑盒测试技术,这种技术把程序的输入域划分成若干个数据类,据此导出测试用例。一个理想的测试用例能独自发现一类错误。
穷尽的黑盒测试通常是不现实的。因此,只能选取少量最有代表性的输入数据作为测试数据,以期用较小的代价暴露出较多的程序错误。
等价划分法力图设计出能发现若干类程序错误的测试用例,从而减少必须设计的测试用例的数目。
边界值分析
经验表明,处理边界情况时程序最容易发生错误。边界值分析是一种测试用例设计技术,它是等价划分的补充。
错误推测*
不同类型不同特点的程序通常又有一些特殊的容易出错的情况。
有时分别使用每组测试数据时程序都能正常工作,这些输入数据的组合却可能检测出程序的错误。
一般说来,即使是一个比较小的程序,可能的输入组合数也往往十分巨大,因此必须依靠测试人员的经验和直觉,从各种可能的测试方案中选出一些最可能引起程序出错的方案。
对于程序中可能存在哪类错误的推测,是挑选测试方案时的一个重要因素。
测试计划、测试分析报告
测试方案
所谓测试方案不仅仅是测试时使用的输入数据(称为测试用例),还应该包括每组输入数据预定要检验的功能,以及每组输入数据预期应该得到的正确输出。实际上测试配置是软件配置的一个子集,最终交出的软件配置应该包括上述测试配置以及测试的实际结果和调试的记录
八、软件维护
软件维护的必要性
维护阶段是软件生命周期的最后一个阶段,其基本任务是保证软件在一个相当长的时期能够正常运行。
软件工程的目的是要提高软件的可维护性,减少软件维护所需要的工作量,降低软件系统的总成本。
软件维护的特点
- 结构化维护:代码+文档+所有你想要的材料
- 非结构化维护:代码+罢工
结构化维护
如果有一个完整的软件配置存在:
- 那么维护工作从评价设计文档开始,确定软件重要的结构特点、性能特点以及接口特点;
- 估量要求的改动将带来的影响,并且计划实施途径。
- 然后首先修改设计并且对所做的修改进行仔细复查。 接下来编写相应的源程序代码;
- 使用在测试说明书中包含的信息进行回归测试;
- 最后,把修改后的软件再次交付使用。
这是在软件开发的早期应用软件工程方法学的结果。
虽然有了软件的完整配置并不能保证维护中没有问题,但是确实能减少精力的浪费并且能提高维护的总体质量。
非结构化维护
如果软件配置的惟一成分是程序代码:
- 那么维护活动从艰苦地评价程序代码开始
- 常常由于程序内部文档不足而使评价更困难
- 对于软件结构、全程数据结构、系统接口、性能和(或)设计约束等经常会产生误解
- 对程序代码所做的改动的后果也是难于估量的
- 因为没有测试方面的文档,所以不可能进行回归测试
- 非结构化维护需要付出很大代价(浪费精力并且遭受挫折的打击)
这种维护方式是没有使用良好定义的方法学开发出来的软件的必然结果。
软件维护的内容(定义)
维护阶段的关键任务是,通过各种必要的维护活动使系统持久地满足用户的需要。
通常有4类维护活动:
- 改正性维护:改正之前存在的bug,17%-21%
- 适应性维护:比如适应不同系统机型,18%-25%
- 完善性维护:为适应后续需要作了一些改进,4%
- 预防性维护:实际软件和需求相比有区别,50%-60%
软件的可维护性:概念
可以把软件的可维护性定性地定义为: 维护人员理解、改正、改动或改进这个软件的难易程度。
提高可维护性是支配软件工程方法学所有步骤的关键目标。
与可维护性有关的软件特性:含义
- 可理解性
- 可测试性
- 可修改性
- 可移植性
- 可重用性
软件问题报告、软件修改报告
软件问题报告
- 用标准化的格式表达所有软件维护要求。
- 软件维护人员给用户提供空白的维护要求表——软件问题报告表,这个表格由要求一项维护活动的用户填写。
- 如果遇到了一个错误,那么必须完整描述导致出现错误的环境(包括输入数据、全部输出数据以及其他有关信息)。
- 对于适应性或完善性的维护要求,应该提出一个简短的需求说明书。
- 由维护管理员和系统管理员评价用户提交的维护要求表。
软件修改报告
维护要求表是一个外部产生的文件,它是计划维护活动的基础。
软件组织内部应该制定出一个软件修改报告,它给出下述信息:
- 满足维护要求表中提出的要求所需要的工作量;
- 维护要求的性质;
- 这项要求的优先次序;
- 与修改有关的事后数据。
在拟定进一步的维护计划之前,把软件修改报告提交给变化授权人审查批准。
九、OO方法
面向对象的方法学可以用下列方程来概括:
OO = objects
+ classes
+ inheritance
+ communication with messages
OO基本概念:对象、类、封装、继承、多态、消息
对象
在应用领域中有意义的、与所要解决的问题有关系的任何事物都可以作为对象,它既可以是具体的物理实体的抽象,也可以是人为的概念,或者是任何有明确边界和意义的东西。
组成
对象由
- 描述对象属性的数据(静态的属性)
- 对这些数据施加的所有操作(动态行为)
封装在一起构成的统一体。
对象的形象表示
对象的特点
- 以数据为中心;
- 对象是主动的;
- 实现了数据封装;
- 本质上具有并行性;
- 模块独立性好。
类(class)
分类是人类认识客观世界的基本方法。
在面向对象的软件技术中,“类”就是对具有相同数据和相同操作的一组相似对象的定义,也就是说,类是对具有相同属性和行为的一个或多个对象的描述。
实例(instance)
实例就是由某个特定的类所描述的一个具体的对象。
封装(encapsulation)
在面向对象的程序中,把数据和实现操作的代码集中起来放在对象内部。
一个对象好像是一个不透明的黑盒子,表示对象状态的数据和实现操作的代码与局部数据,都被封装在黑盒子里面,从外面是看不见的,更不能从外面直接访问或修改这些数据和代码。
使用一个对象的时候,只需知道它向外界提供的接口形式,无须知道它的数据结构细节和实现操作的算法。
继承(inheritance)
- 广义地说,继承是指能够直接获得已有的性质和特征,而不必重复定义它们。
- 在面向对象的软件技术中,继承是子类自动地共享基类中定义的数据和方法的机制。
- 继承具有传递性。
- 使用从原有类派生出新的子类的办法,使得对软件的修改变得比过去容易得多了。
- 继承性使得用户在开发新的应用系统时不必完全从零开始,可以继承原有的相似系统的功能或者从类库中选取需要的类,再派生出新的类以实现所需要的功能。
多态(polymorphism)
多态性一词来源于希腊语,意思是“有许多形态”
在面向对象的软件技术中,多态性是指子类对象可以像父类对象那样使用,同样的消息既可以发送给父类对象也可以发送给子类对象。
也就是说,在类等级的不同层次中可以共享(公用)一个行为(方法)的名字,然而不同层次中的每个类却各自按自己的需要来实现这个行为。当对象接收到发送给它的消息时,根据该对象所属于的类动态选用在该类中定义的实现算法。
假设B继承自A,那么
A a=new B()
,那么假设A和B中都有m()
方法,a.m()
调用的是B中的m()
方法
消息(message)
消息就是要求某个对象执行在定义它的那个类中所定义的某个操作的规格说明。通常,一个消息由下述3部分组成:
- 接收消息的对象;
- 消息选择符(也称为消息名);
- 零个或多个变元。
方法(method)
方法就是对象所能执行的操作,也就是类中所定义的服务。
方法描述了对象执行操作的算法,响应消息的方法。
属性(attribute)
属性就是类中所定义的数据,它是对客观世界实体所具有的性质的抽象。
类的每个实例都有自己特有的属性值。
重载(overloading)
两种重载
- 函数重载是指在同一作用域内的若干个参数特征不同的函数可以使用相同的函数名字;
- 运算符重载是指同一个运算符可以施加于不同类型的操作数上面
OO优点
- 与人类习惯的思维方法一致
- 稳定性好
- 可重用性好
- 较易开发大型软件产品
- 可维护性好
OOA(面向对象分析 ):OOA任务
不论采用哪种方法开发软件,分析的过程都是提取系统需求的过程
分析工作主要包括3项内容:
- 理解
- 表达
- 验证
面向对象分析(OOA)的关键是识别出问题域内的类与对象,并分析它们相互间的关系,最终建立起问题域的简洁、精确、可理解的正确模型
OOA分析过程
- 从use-case的定义开始;
- 然后应用CRC建模技术来为类和它们的属性与操作建立文档;
- 然后是对象的分类和类层次的创建对象模型,类图、顺序图、用例图
OOD(面向对象设计):OOD任务与过程
高层设计模型:Client/Server MVC
类的设计(复用类)
任务(应该是这个?)
在面向对象系统中,你将发现类和通信对象的重复出现的模式。这些模式解决特定的设计问题,并使得面向对象设计更灵活、优美和最终可复用。
他们通过将新的设计基于以前的经验之上而帮助设计者复用成功的设计,熟悉这样模式的设计者可以立即应用他们到设计问题中,而不需要重新去发现他们。
准则
- 模块化
- 抽象
- 信息隐藏
- 弱耦合
- 强内聚
- 可重用
类的设计
面向对象技术中的“类”,是比较理想的可重用软构件,不妨称之为类构件
可重用软构件应具备的特点
(1) 模块独立性强
(2) 具有高度可塑性
(3) 接口清晰、简明、可靠
类构件的重用方式
(1) 实例重用
使用适当的构造函数,按照需要创建类的实例
还可以用几个简单的对象作为类的成员创建出一个更复杂的类
(2) 继承重用
关键是设计一个合理的、具有一定深度的类构件继承层次结构
(3) 多态重用
使对象的对外接口更加一般化(基类与派生类的许多对外接口是相同的)
系统运行时,根据接收消息的对象类型,由多态性机制启动正确的方法,去响应一个一般化的消息
面向对象设计模型的逻辑组成
- 问题域子系统
- 人机交互子系统
- 任务管理子系统
- 数据管理子系统。
OOT(面向对象测试):
OOT的困难
问题未在分析过程中被发现,传播到设计阶段产生的问题
- 在系统设计阶段可能将类不合适的分配到子系统或任务。
- 可能花费不必要的工作去创建针对无关属性的操作的过程设计。
- 消息模型将是不正确的(因为必须为无关的操作设计消息)。
- 如果问题在设计阶段仍然未被检测到,传到编码活动中会产生更多的问题。
测试OOA和OOD模型
- OOA和OOD模型的正确性
- OOA和OOD模型的一致性
OOT步骤
OO测试在策略上和传统系统的测试类似,但是,战术技巧上存在不同。因为OO分析和设计模型在结构上类似于最终OO程序的内容,“测试”从对这些模型的评审开始。
一旦代码生成,OO测试开始“小规模”类测试。一系列测试被设计以检查类操作并检查当某类和其他类协作时是否有错误发生。类被集成以形成子系统,用于完全地测试协作类。最后,user-case被用于发现在软件确认级的错误。
OOT重要性
你必须在将程序交付给客户之前执行程序以试图消除所有错误,从而使客户将不会经历由于质量差所带来的挫折。
为了发现最大可能数量的错误,测试必须被系统化地进行,必须用严格的技术来设计测试案例。
十、UML
UML的9种图形及其适用情况
UML模型图(5类,10种):
- 用例图
- 静态图(类图,对象图,包图)
- 行为图(状态图,活动图)
- 交互图(顺序图,合作图)
- 实现图(构件图,配置图)
用例图
从本质上将,一个用例是用户与计算机之间为达到某个目的的一次典型交互作用:
- 用例描述了用户提出的一些可见的需求;
- 用例可大可小;
- 用例对应一个具体的用户目标
用例图描述系统外部的执行者与系统的用例之间的某种联系。
- 所谓用例是指对系统提供的功能(或称系统的用途)的一种描述;
- 执行者是那些可能使用这些用例的人或外部系统;
- 用例和执行者之间的联系描述了“谁使用哪个用例”。
用例图着重于从系统外部执行者的角度来描述系统需要提供哪些功能,并且指明了这些功能的执行者是谁;
用例图在UML方法中占有十分重要的地位,人们甚至称UML是一种用例图驱动的开发方法。
符号
示例
类图
在面向对象的建模技术中,类、对象和它们之间的关系是最基本的建模元素。对于一个想要描述的系统,其类模型、对象模型以及它们之间的关系揭示了系统的结构。
类图描述了系统中的类及其相互之间的各种关系,其本质反映了系统中包含的各种对象的类型以及对象间的各种静态关系(关联,子类型)。
符号
类中的基本符号
类图描述类及类与类之间的静态关系。
类图是一种静态模型,它是创建其他UML图的基础。
- 定义类
UML中类的图形符号为长方形,分成3个区域(下面两个区域可省略),分别放类的名字、属性和服务。
- 定义属性
UML描述属性的语法格式如下:
可见性 属性名: 类型名=初值{性质串}
属性的可见性(即可访问性):
- 公有的(public):加号(+)
- 私有的(private):减号(-)
- 保护的(protected):井号(#)
注意,没有默认的可见性。
- 定义服务
服务也就是操作
UML描述操作的语法格式如下:
可见性 操作名(参数表): 返回值类型{性质串}
操作可见性的定义方法与属性相同。
参数表是用逗号分隔的形式参数的序列。
描述一个参数的语法如下:
参数名: 类型名=默认值
示例
对象图
对象图是类图的一种变形。除了在对象名下面要加下划线以外,对象图中所使用的符号与类图基本相同。
对象图是类图的一种实例化。一张对象图表示的是与其对应的类图的一个具体实例,即系统在某一时期或者某一特定时刻可能存在的具体对象实例以及它们相互之间的具体关系。
对象图并不象类图那样具有重要的地位,但是利用它可以帮助我们通过具体的实例分析,更具体直观地了解复杂系统类图的丰富内涵。
对象图还常常被用作合作图的一部分,用以展示一组对象实例之间的动态协作关系。
示例
顺序图
顺序图描述了对象之间动态的交互关系,着重体现对象间消息传递的时间顺序。
顺序图由一组对象构成,每个对象分别带有一条竖线,称作对象的生命线,它代表时间轴,时间沿竖线向下延伸。顺序图描述了这些对象随着时间的推移相互之间交换消息的过程。消息用从一条垂直的对象生命线指向另一个对象的生命线的水平箭头表示。图中还可以根据需要增加有关时间的说明和其他注释。
顺序图中的事件顺序:
- 因果性(Causality):对同一消息而言,发送事件先于接收事件。
- 可控性(Controlability):对同一对象而言,事件p出现在发送事件q的上方,则p先于q。
- 队列性(FIFO):对同一对象而言,接收事件p出现在接收事件q的上方,并且它们分别对应的发送事件也位于同一个对象,则p先于q。
示例
UML图形中的关系类型(使用、扩展、泛化、关联、聚集、依赖)
关联
关联表示两个类的对象之间存在某种语义上的联系。例如,作家使用计算机,我们就认为在作家和计算机之间存在某种语义连接,因此,在类图中应该在作家类和计算机类之间建立关联关系。
在表示关联的直线两端可以写上重数(multiplicity),它表示该类有多少个对象与对方的一个对象连接。重数的表示方法通常有:
- 0…1:表示0到1个对象
- 0…*或*:表示0到多个对象
- 1+或1…*:表示1到多个对象
- 1…15:表示1到15个对象
- 3:表示3个对象
如果图中未明确标出关联的重数,则默认重数是1。
关联的角色
在任何关联中都会涉及到参与此关联的对象所扮演的角色(即起的作用),在某些情况下显式标明角色名有助于别人理解类图。
限定关联
限定关联通常用在一对多或多对多的关联关系中,可以把模型中的重数从一对多变成一对一,或从多对多简化成多对一。在类图中把限定词放在关联关系末端的一个小方框内。
例如,某操作系统中一个目录下有许多文件,一个文件仅属于一个目录,在一个目录内文件名确定了惟一一个文件。利用限定词“文件名”表示了目录与文件之间的关系,利用限定词把一对多关系简化成了一对一关系。
关联类
为了说明关联的性质可能需要一些附加信息。可以引入一个关联类来记录这些信息。关联中的每个连接与关联类的一个对象相联系。关联类通过一条虚线与关联连接。
聚集
聚集也称为聚合,是关联的特例。
聚集表示类与类之间的关系是整体与部分的关系。
在陈述需求时使用的“包含”、“组成”、“分为……部分”等字句,往往意味着存在聚集关系。除了一般聚集之外,还有两种特殊的聚集关系,分别是共享聚集和组合聚集。
共享聚集
如果在聚集关系中处于部分方的对象可同时参与多个处于整体方对象的构成,该聚集称为共享聚集。
例如,一个课题组包含许多成员,每个成员又可以是另一个课题组的成员,则课题组和成员之间是共享聚集关系。
一般聚集和共享聚集的图示符号,都是在表示关联关系的直线末端紧挨着整体类的地方画一个空心菱形。
组合聚集
如果部分类完全隶属于整体类,部分与整体共存,整体不存在了部分也会随之消失(或失去存在价值了),则该聚集称为组合聚集(简称为组成)。
例如,在屏幕上打开一个窗口,它就由文本框、列表框、按钮和菜单组成,一旦关闭了窗口,各个组成部分也同时消失,窗口和它的组成部分之间存在着组合聚集关系。
泛化
UML中的泛化关系就是通常所说的继承关系,它是通用元素和具体元素之间的一种分类关系。
具体元素完全拥有通用元素的信息,并且还可以附加一些其他信息。
在UML中,用一端为空心三角形的连线表示泛化关系,三角形的顶角紧挨着通用元素。
注意,泛化针对类型而不针对实例实际上,泛化关系指出在类与类之间存在“一般-特殊”关系。
泛化可进一步划分成普通泛化和受限泛化。
普通泛化
普通泛化与继承基本相同。
没有具体对象的类称为抽象类。抽象类通常作为父类,用于描述其他类(子类)的公共属性和行为。图示抽象类时,在类名下方附加一个标记值**{abstract}**
举个两个抽象类的例子
如图所示。图下方的两个折角矩形是模型元素“笔记”的符号,其中的文字是注释,分别说明两个子类的操作drive的功能。
抽象类通常都具有抽象操作。抽象操作仅用来指定该类的所有子类应具有哪些行为。抽象操作的图示方法与抽象类相似,在操作标记后面跟随一个性质串{abstract}。
与抽象类相反的类是具体类,具体类有自己的对象,并且该类的操作都有具体的实现方法。
受限泛化
可以给泛化关系附加约束条件,以进一步说明该泛化关系的使用方法或扩充方法,这样的泛化关系称为受限泛化。预定义的约束有4种: 多重、不相交、完全和不完全。这些约束都是语义约束。
依赖
依赖关系描述两个模型元素(类、用例等)之间的语义连接关系: 其中一个模型元素是独立的,另一个模型元素不是独立的,它依赖于独立的模型元素,如果独立的模型元素改变了,将影响依赖于它的模型元素。
友元依赖关系
在UML的类图中,用带箭头的虚线连接有依赖关系的两个类,箭头指向独立的类。在虚线上可以带一个版类标签,具体说明依赖的种类,例如,下图表示一个友元依赖关系,该关系使得B类的操作可以使用A类中私有的或保护的成员。
细化关系
- 当对同一个事物在不同抽象层次上描述时,这些描述之间具有细化关系。
- 假设两个模型元素A和B描述同一个事物,它们的区别是抽象层次不同,如果B是在A的基础上的更详细的描述,则称B细化了A,或称A细化成了B。
- 细化的图示符号为由元素B指向元素A的、一端为空心三角形的虚线(注意,不是实线)。
- 细化用来协调不同阶段模型之间的关系,表示各个开发阶段不同抽象层次的模型之间的相关性,常常用于跟踪模型的演变。
十一、软件质量管理
软件质量定义
软件与明确地和隐含地定义的需求相一致的程度
软件质量模型
(参考来源:知乎:anscj《软件质量模型》)
6个软件质量特性(功能性、可靠性、可用性、效率、可维护性、可移植性)
(参考来源:知乎:anscj《软件质量模型》)
功能性
当软件在指定条件下使用时,软件产品提供满足明确和隐含要求的功能的能力。
- 适合性:为指定的任务和用户目标提供一组合适的功能的能力
- 准确性:提供具有所需精度的正确或相符的结果或效果的能力
- 互操作性:与一个或更多的规定系统进行交互的能力
- 安全保密性:保护信息和数据的能力,以使未授权的人员或系统不能阅读或修改这些信息和数据,而不拒绝授权人员或系统对它们的访问
可靠性
软件产品维持规定的性能级别的能力。
- 成熟性:避免由软件中故障而导致失效的能力
- 容错性:在软件出现故障或者违反指定接口的情况下,软件产品维持规定的性能级别的能力
- 易恢复性:在失效发生的情况下,软件产品重建规定的性能级别并恢复受直接影响的数据的能力
易用性
产品被理解、学习、使用和吸引用户的能力。
- 易理解性:使用户能理解软件是否合适以及如何能将软件用于特定的任务和使用条件的能力
- 易学性:使用户能学会其应用的能力
- 易操作性:使用户能操作和控制的能力
- 吸引性:吸引用户的能力
效率
相对于所用资源的数量,软件产品可提供适当性能的能力。
- 时间特性:执行功能时,提供适当的响应和处理时间以及吞吐率的能力
- 资源利用性:执行功能时,使用合适数量和类别的资源的能力
维护性
可被修改的能力。修改可能包括纠正、改进或软件对环境、需求和功能规格说明变化的适应。
- 易分析性:可被诊断自身的缺陷/失效原因或标识其待修改部分的能力
- 易改变性:使指定的修改可以被实现的能力
- 稳定性:避免因软件修改而造成意外结果的能力
- 易测试性:使已修改的软件能被确认的能力
可移植性
从一种环境转移到另一种环境的能力。
- 适应性:无须采用额外的活动或手段就可适应不同的指定环境的能力
- 易安装性:在指定环境中被安装的能力
- 共存性:在公共环境中同与其分享公共资源的其他软件共存的能力
- 易替换性:在同样环境下,替代另一个相同用途的指定软件产品的能力
CMM概念与结构
概念
美国卡内基梅隆大学软件工程研究所在美国国防部资助下于20世纪80年代末建立的能力成熟度模型(capability maturity model,CMM),是用于评价软件机构的软件过程能力成熟度的模型。
目的
最初,建立此模型的目的主要是,为大型软件项目的招投标活动提供一种全面而客观的评审依据,发展到后来,此模型又同时被应用于许多软件机构内部的过程改进活动中。
基本思想
能力成熟度模型的基本思想是,由于问题是由我们管理软件过程的方法不当引起的,所以新软件技术的运用并不会自动提高软件的生产率和质量。
CMM在改进软件过程中的主要作用
- 指导软件机构通过确定当前的过程成熟度并识别出对过程改进起关键作用的问题,从而明确过程改进的方向和策略。
- 通过集中开展与过程改进的方向和策略相一致的一组过程改进活动,软件机构便能稳步而有效地改进其软件过程,使其软件过程能力得到循序渐进的提高。
- 对软件过程的改进,是在完成一个又一个小的改进步骤基础上不断进行的渐进过程,而不是一蹴而就的彻底革命。
- CMM把软件过程从无序到有序的进化过程分成5个阶段,并把这些阶段排序,形成5个逐层提高的等级。
- 这5个成熟度等级定义了一个有序的尺度,用以测量软件机构的软件过程成熟度和评价其软件过程能力,这些等级还能帮助软件机构把应做的改进工作排出优先次序。
- 成熟度等级是妥善定义的向成熟软件机构前进途中的平台,每个成熟度等级都为软件过程的继续改进提供了一个台阶
内容(结构)
- 5级标准
- 初始级(又称为1级)
- 可重复级(又称为2级)
- 已定义级(又称为3级)
- 已管理级(又称为4级)
- 优化级(又称为5级)
- 18个KPA
初始级-无序过程
可重复级
- 需求管理
- 软件项目管理
- 软件项目跟踪与监控
- 软件转包合同管理
- 软件质量保证
- 软件配置管理
已定义级
- 集成软件管理
- 组间协调
- 组织过程焦点
- 组织过程定义
- 培训程序
- 软件产品工程
- 同级评审
可管理级
- 定量过程管理
- 软件质量管理
优化级
- 技术改革管理
- 过程变革管理
- 缺陷防范
- 目标
- 关键实践-KP
十二、项目管理
项目的概念与主要特征
概念
项目是一件事情、一项独一无二的任务,也可以理解为是在一定的时间和一定的预算内所要达到的预期目的。
主要特征
1、一次性
这是项目与日常运作的最大区别。项目有明确的开始时间和结束时间,项目在此之前从来没有发生过,而且将来也不会在同样的条件下再发生,而日常运作是无休止或重复的活动。
2、独特性
每个项目都有自己的特点,每个项目都不同于其他的项目。项目所产生的产品、服务或完成的任务与已有的相似产品、服务或任务在某些方面有明显的差别。项目自身有具体的时间期限、费用和性能质量等方面的要求。因此,项目的过程具有自身的独特性。
3、目标的明确性
每个项目都有自己明确的目标,为了在一定的约束条件下达到目标,项目经理在项目实施以前必须进行周密的计划,事实上,项目实施过程中的各项工作都是为项目的预定目标而进行的。
4、组织的临时性和开放性
项目开始时需要建立项目组织,项目组织中的成员及其职能在项目的执行过程中将不断地变化,项目结束时项目组织将会解散,因此项目组织具有临时性。一个项目往往需要多个甚至几百上千个单位共同协作,它们通过合同、协议以及其他的社会联系组合在一起,可见项目组织没有严格的边界。
5、后果的不可挽回性
项目具有较大的不确定性,它的过程是渐进的,潜伏着各种风险。它不像有些事情可以试做,或失败了可以重来,即项目具有不可逆转性。
项目管理的概念和内容
概念
有效的项目管理集中于三个P 上:People、Problem、Process
内容
People
- 项目参与者
- 项目负责人
- 软件项目组
- 协调和通讯
Problem
- 软件范围
- 问题分解
Process
- 合并问题和过程
- 过程分解
项目目标管理的要素
工作范围、时间、质量、成本。
学习笔记,仅供参考,如有错误,敬请指正!