一 什么是软件危机?它有哪些典型表型?为什么会出现软件危机?
软件危机的介绍:软件危机是指在计算机开发和维护过程中所遇到的一系列严重的问题
主要包含以下两个问题:
1.如何开发软件,以满足对软件日益增长的需求
2.如何维护数量不断膨胀的已有软件
软件危机的典型表现:
1.对软件开发成本和进度的估计常常不准确
2.用户对“已完成的”软件系统不满意的现象经常发生
3.软件产品的质量往往靠不住
4.软件常常是不可维护的
5.软件通常没有适当的文档资料
6.软件成本在计算机系统总成本中所占的比例逐年上升
7.软件开发生产的速率,跟不上计算机应用迅速普及深入的趋势
产生软件危机的原因
一方面与软件本身的特点有关,另一方面也与软件开发与维护的方法不正确。
二:什么是软件工程?它有哪些本质特性?怎样用软件工程消除软件危机?
软件工程的介绍:软件工程是指导计算机软件开发和维护的一门工程学科。
软件工程的出现原因:软件工程是为了解决软件危机而出现的
软件工程的本质特性
(1)软件工程关注于大型程序的构造
(2)软件工程的中心课题是控制复杂性
(3)软件经常变化
(4)开发软件的效率非常重要
(5)和谐地合作是开发软件的关键
(6)软件必须有效地支持它的用户
(7)软件工程领域中通常由具有一种文化背景的人代替具有另一种文化背景的人创造产品。
软件工程的基本原理
1.用分阶段的生命周期计划严格管理
2.坚持进行阶段评审
3.实行严格的产品控制
4.采用现代程序技术
5.结果应能清楚地审查
6.开发小组人员应该少而精
7.承认不断改进软件工程实践的必要性
软件危机应付途径
运用软件工程技术消除软件危机,具体做法:
1.对计算机软件有一个正确的认识(软件≠程序)
2.必须充分认识到软件开发不是某种个体劳动的神秘技巧,而应该是一种组织良好,管理严密,各类人员协同配合,共同完成的工程项目。
3.推广使用在实践中总结出来的开发软件的成功技术和方法
4.开发和使用更好的开发工具
软件工程方法学包含3个要素:方法,工具和过程。
软件生命周期是由软件定义,软件开发和运行维护(也称为软件维护)3个时期组成,每个时期又进一步划分成若干个阶段。
软件定义时期可以划分为3个阶段,即问题定义,可行性研究和需求分析。
软件开发时期通常划分为4个阶段,即总体设计,详细设计,编码和单元测试,综合测试。
软件维护时期不再进一步划分阶段,但是每一次维护活动本质上都是一次压缩和简化了的定义和开发过程。
每个时期的任务
1.软件定义时期的任务:确定软件开发工程必须完成的总目标;确定工程的可行性;导出实现工程目标应该采用的策略以及系统必须完成的功能;估计完成该项工程需要的资源和成本,并且制定工程进度表。
2.开发时期的任务:具体设计和实现在前一个时期定义的软件。
3.维护时期的任务:使软件持久地满足用户的需要。
7.常见三种周期模型的优点
瀑布模型的优点:
1.可强迫开发人员采用规范的方法(例如:结构化技术)
2.严格地规定了每个阶段必须提交的文档;
3.要求每个阶段交出的所有产品都必须经过质量保证小组的仔细验证
快速原形模型的优点:
1.有助于保证用户的真实需要得到满足
增量模型的优点:
1.能在较短的时间内向用户提交可完成部分工作的产品
2.逐步增加产品功能可以使用户有较充裕的时间学习和适应新产品,从而减少
一个全新的软件可能给客户组织带来的冲击。
3.软件的可维护性明显好于封闭结构的软件
三:说明微软过程的适用范围
适用于商业环境下具有有限资源和有限开发时间约束的项目的软件过程模式
第二章 可行性研究
可行性研究分为:
数据字典是关于数据的信息的集合,也就是对数据流图中包含的所有元素的定义的集合
数据字典的内容
一般说来,数据字典应该由对下列4类元素的定义组成
第三章 需求分析
3.1需求分析的任务
虽然功能需求是对软件系统的一项基本需求,但却并不是唯一的需求。通常对软件系统有下述几方面的综合要求
数据模型中包含3种相互关联的信息:数据对象,数据对象的属性以及数据对象彼此间相互连接的关系
3.4.1数据对象
3.4.2 属性
3..4.3 联系
第四章 形式化说明技术
4.1概述
一:按形式化程度分为三类:
非形式化,如用自然语言描述规格说明
半形式化,如用数据流图或实体-联系图建立模型
形式化,如描述系统性质是基于数学的技术
二:非形式化的缺点
矛盾性:在需求规格说明书中对同一问题前后存在不同的描述
二义性:读者可以用不同的方式理解的陈述
含糊性:需求规格说明书对某一问题描述不清晰,不可理解
不完整性:需求规格说明书对某一问题只说明了局部,没说明整体
抽象层次混乱:指在非常抽象的陈述中混入了关于低层次的细节陈述
三:形式化的优点:
能够简洁准确的描述物理现象、对象或动作的结果
在不同的软件工程活动之间平滑过渡
提供了高层确认的手段
四:应用形式化准则
选用适当的表示方法
应该形式化,但不要过分形式化
应该估算成本
应该有形式化顾问随时提供咨询
不应该放弃传统的开发方法
应该建立详尽的文档
不应该放弃质量标准
应该测试,测试再测试
应该重用
有穷状态机的概念在计算机系统中应用得非常广泛。
例如,每个菜单驱动的用户界面都是一个有穷状态机的实现。一个菜单的显示和一个状态相对应,键盘输入或用鼠标选择一个图标是使系统进入其他状态的一个事件。状态的每个转换都具有下面的形式:
当前状态〔菜单〕+事件〔所选择的项〕=>下个状态。
为了对一个系统进行规格说明,通常都需要对有穷状态机做一个很有用的扩展,即在前述的5元组中加入第6个组件——谓词集P,从而把有穷状态机扩展为一个6元组,其中每个谓词都是系统全局状态Y的函数。转换函数T现在是一个从(J-F)×K×P到J的函数。现在的转换规则形式如下:
当前状态〔菜单〕+事件〔所选择的项〕+谓词=>下个状态。
系统设计阶段
:确定系统的具体实现方案 和 结构设计阶段
:确定软件结构); 9个步骤: 设计原理的相关概念
模块化:就是把程序划分成独立命名且可独立访问的模块,每个模块完成一个子功能,这些模块集成起来构成一个整体,可以完成指定的功能满足用户的需求
抽象:抽出事物本质特性而暂时不考虑细节
逐步求精:为了能集中精力解决最主要问题而尽量推迟对问题细节的考虑。逐步求精是人类解决复杂问题时采用的基本方法,也是许多软件工程技术的基础
信息隐藏:应该这样设计和确定模块,使得一个模块内包含的信息对于不需要这些信息的模块来说是不能访问的
局部化:是指把一些关系密切的软件元素物理地址放得彼此靠近
模块独立:是模块化、抽象、信息隐藏和局部化的概念的直接结果。独立的程度测量标准:内聚、耦合
耦合:是对一个软件结构内不同模块之间互连程度的度量。耦合强弱取决于模块间接口的复杂程度,进入或访问一个模块的点,以及通过接口的数据。耦合程度强烈影响着系统的可理解性、可测试性、可靠性、可维护性。设计原则:尽量使用数据耦合,少用控制耦合和特征耦合,限制公共环境的耦合的范围,完全不用内容耦合。
数据耦合:如果两个模块彼此间通过参数交换信息,而且交换的信息仅仅是数据。数据耦合是低耦合
控制耦合:传递的信息中有控制信息。中等耦合,增加了系统的复杂性
特征耦合:当整个数据结构作为参数传递而被调用的模块只需要使用其中一部分数据元素时
公共环境耦合:当两个或多个模块通过一个公共数据环境互相作用时。公共环境可以是全程变量、共享通信区、内存的公共覆盖区、任何存储介质的文件、物理设备等。
内容耦合:如果发生之一就是①一个模块访问另一个模块的内部数据,②一个模块不通过正常入口而转到另一个模块的内部,③两个模块有一部分程序代码重叠,④一个模块有多个入口
内聚:标志着一个模块内各个元素彼此之间结合的紧密程度,它是信息隐藏和局部化概念的扩展。设计原则:力求高内聚,通过提高模块间的内聚降低耦合从而使模块获得较高的独立性。高内聚意味着低耦合
低内聚
偶然内聚:如果一个模块完成一组任务,这些任务彼此之间有关系,关系也是很松散的。如在一个程序内有一组语句在两处或多处出现,于是把这些语句作为一个模块以节省内存
逻辑内聚:如果一个模块完成的任务在逻辑上属于相同或相似的一类。如一个模块产生各种类型的全部输出
时间内聚:如果一个模块包含的任务必须在同一时间内执行。如模块完成各种初始化工作
中内聚
过程内聚:如果一个模块内的处理元素是相关的,且必须以特定次序执行。如流程图确定模块的划分,得到的往往是过程内聚的模块
通信内聚:如果一个模块中所有元素都是用同一个输入数据和产生同一个输出数据
高内聚
顺序内聚:如果一个模块内的处理元素和同一个功能密切相关,且这些处理必须顺序执行。如一个处理元素的输出数据作为下一个处理元素的输入数据,根据数据流图划分模块得到往往是顺序内聚模块
功能内聚:如果模块内的所有处理元素属于一个整体,完成单一的功能
7种内聚的优劣评分
名称 得分
功能内聚 10
顺序内聚 9
通信内聚 7
过程内聚 5
时间内聚 3
逻辑内聚 1
偶然内聚 0
47. 启发规则
改进软件结构提高模块的独立性
模块规模应该适中
深度、宽度、扇出和扇入都应适当
模块的作用域应该在控制域内
力争降低模块接口的复杂程度
设计单入口单出口的模块
模块的功能应该可预测
描绘软件结构的图形工具(例子见P102,P103)
层次图:描绘软件的层次结构。一个矩形框代表一个模块,方框间的连线表示调用关系
HIPO图:“层次图加输入/处理/输出图”,就是在层次图的每个方框加编号
结构图:每个方框代表一个模块,框内注明模块的名字或主要功能,方框间的箭头(或直线)代表模块的调用关系,注释表示来回传递的信息【尾部空心圆表示传递数据,实心圆代表传递控制信息】
第六章 详细设计
6.1结构化程序设计
详细设计
根本目标:确定应该怎样具体地实现所要求的系统。
详细设计阶段的任务不是具体地编写程序,而是要设计出程序的“蓝图”。
详细设计的结果基本上决定了最终的程序代码的质量。
2.1 结构程序设计
结构程序设计经典定义:如果一个程序的代码块仅仅通过顺序、选择和循环这3种基本控制结构进行连接,并且每个代码块只有一个入口和一个出口,则称这个程序是结构化的。
结构程序设计更全面的定义:结构程序设计是尽可能少用GO TO语句的程序设计方法。最好仅在检测出错误时才使用GO TO语句,而且应该总是使用前向GO TO语句。
6.2人机界面设计
系统响应时间。用户帮助设施。出错信息处理。命令交互
程序流程图:
优点:对控制流程的描绘直观,初学者很容易掌握
缺点:①程序流程图不是精益求精的好工具吗,它诱使程序员过早地考虑程序的控制流程,而不去考虑全局结构
②程序流程图中用箭头代表控制流 ,因此程序员不受任何约束,可以完全不顾结构程序设计的思想,随意转移
③程序流程图不易表示数据结构
盒图(N-S图)的特点:
功能域明确
不可能任意转移控制
很容易确定局部和全局数据的作用域
很容易表现嵌套关系,也可以表示模块的层次结构
问题分析图(PAD图):使用二维结构的图来表示程序的控制流。其优点:
使用PAD符号设计出来必然是结构化程序
PAD图描绘的程序结构十分清楚
PAD图表现程序的逻辑,易读、易懂、易记
很容易将PAD图转化为高级语言程序
即可表示程序逻辑,也可表示数据结构
PAD符号支持自动向下,逐步求精
判定表:当算法中含有多重嵌套的条件选择时
优点:能清晰表示复杂的条件组合与应做的动作之间的关系
缺点:①判定表的含义不能一眼看出来②当数据元素多于两个时,判定表的简洁程度下降
判定树:判定表变种
优点:一眼看出其含义,易于掌握,使用
缺点:①简洁性不如判定表,数据元素需重复写多遍②判定树的分支次序对画出的判定树的简洁程度有较大影响
PDL(过程设计语言):也称伪码,具有严格的关键字外部语法,用于定义控制结构和数据结构,内部语法灵活自由,适应各种工程项目。
其优点:
可作为注释直接插在源程序中间
可使用普通的正文编辑程序或文字处理系统完成PDL的书写和编辑
已有自动处理PDL的程序,可自动生成程序代码
其缺点:
不如图形工具形象直观,描述复杂的条件组合与动作间的对应关系时,不如判定表清晰简单
McCabe方法:McCabe根据程序控制流的复杂程度度量 程序的复杂程度,这样度量出的结果称为程序的环形复杂度
①流图的表示:
结点:用圆表示,一个圆代表一条或多条语句
边:箭头线称为边,代表控制流
区域:由边和结点围成的面积 称为区域,当计算区域数时应该包括图外未被围起来的区域
判定结点:包含条件的结点
②计算环形复杂度的方法:
流图中线性无关的区域数等于环形复杂度
流图G的环形复杂度V(G)=E-N+2,其中E是流图中边的条数,N是结点数
流图G的环形复杂度V(G)=P+1,其中P是流图中判定结点的数目
第7章 实现
实现包含:通常把编码和测试统称为实现
编码需要注意什么
自己看书
这一小节,是对软件测试的整体性概括,包括定义,测试方法,步骤等等。
第八章 维护
软件维护的定义:就是在软件已经交付使用之后,为了改正错误或满足新的需要而修改软件的过程
2.1.1 改正性维护
因为软件测试不可能暴露出一个大型软件系统中所有潜藏的错误,所以必然会有第一项维护活动: 在任何大型程序的使用期间,用户必然会发现程序错误,并且把他们遇到的问题报告给维护人员。把诊断和改正错误的过程称为改正性维护。
2.1.2 适应性维护
因此,适应性维护,也就是为了和变化了的环境适当地配合而进行的修改软件的活动,是既必要又经常的维护活动。
2.1.3 完善性维护
当一个软件系统顺利地运行时,常常出现第三项维护活动:在使用软件的过程中用户往往提出增加新功能或修改已有功能的建议,还可能提出一般性的改进意见。为了满足这类要求,需要进行完善性维护。这项维护活动通常占软件维护工作的大部分。
2.1.4 预防性维护
2.3.1 软件维护的本质
维护过程本质上是修改和压缩了的软件定义和开发过程,而且事实上远在提出一项维护要求之前,与软件维护有关的工作已经开始了。
首先必须建立一个维护组织
随后必须确定报告和评价的过程
而且必须为每个维护要求规定一个标准化的事件序列
当为了改进未来的可维护性或可靠性,或为了给未来的改进奠定更好的基础而修改软件时,出现了第四项维护活动。这项维护活动通常称为预防性维护,目前这项维护活动相对比较少
结构化维护和非结构化维护
①非结构化维护
- 如果软件配置的唯一成分是程序代码,那么维护活动从评价代码开始,而且由于内部文档不足而使评价更困难
- 非结构化维护需要付出巨大代价,是没有使用良好定义的方法学开发出来的必然结果
②结构化维护
如果有一个完整软件配置存在,那么维护从评价设计文档开始就很规范
减少精力的浪费,提高维护的总体质量
8.4软件的可维护性
8.4.1 决定软件可维护性的因素
可理解性
可测试性
可修改性
可移植性
可重用性
第八章 面向对象方法学引论
1.面向对象方法学要点:
①基本原则:尽可能模拟人类习惯的思维方式,是开发软件的方法和过程尽可能接近人类认识的世界解决问题的方法和过程
②4个要点
软件是由对象组成的,任何元素都是对象,复杂软件对向由比较简单的软件对象组成
所有对象都划分成对象类,类都定义了一组数据和一组方法
若干对象类组成一个层次的系统
对象间仅能通过传递消息互相联系
③面向对象方法学优点
与人类习惯的思维方法一致
稳定性好
可重用性好
较易开发大型软件产品
可维护性好
对象:是描述该对象属性的数据以及对这些数据施加的所有操作封装在一起构成的统一体
①对象的定义
对象是具有相同状态的一组操作的集合
对象是对问题域中某个东西的抽象
对象::=
2.5 动态模型
动态模型表示瞬时的、行为化的系统的“控制”性质,它规定了对象模型中的对象的合法变化序列。
所有对象都具有自己的生命周期(或称为运行周期)。生命周期中的阶段就是对象的状态。状态是对对象属性值的一种抽象。各对象之间相互触发(即作用)就形成了一系列的状态变化。人们把一个触发行为称作一个事件。对象对事件的响应,取决于接受该触发的对象当时所处的状态,响应包括改变自己的状态或者又形成一个新的触发行为。
状态有持续性,它占用一段时间间隔。状态与事件密不可分,一个事件分开两个状态,一个状态隔开两个事件。事件表示时刻,状态代表时间间隔。
通常,用UML提供的状态图来描绘对象的状态、触发状态转换的事件以及对象的行为(对事件的响应)。
每个类的动态行为用一张状态图来描绘,各个类的状态图通过共享事件合并起来,从而构成系统的动态模型。也就是说,动态模型是基于事件共享而互相关联的一组状态图的集合。
2.6 功能模型
功能模型表示变化的系统的“功能”性质,它指明系统应该“做什么”,因此更直接地反映了用户对目标系统的需求。
功能模型由一组数据流图组成。建立功能模型有助于软件开发人员更深入地理解问题域,改进和完善自己的设计。
UML提供的用例图是进行需求分析和建立功能模型的强有力工具。在UML中把用用例图建立起来的系统模型称为用例模型。
使用用例模型代替传统的功能说明,往往能够更好地获取用户需求,它所回答的问题是“系统应该为每个(或每类)用户做什么”。
用例模型描述的是外部行为者(actor)所理解的系统功能。用例模型的建立是系统开发者和用户反复讨论的结果,它描述了开发者和用户对需求规格所达成的共识。
第十章:面向对象分析
①三个子模型,按所解决的问题进行划分
②5个层次
③对象模型创建的步骤
第十一章 面向对象设计
为什么要面向对象设计 好处,准则因素
1 面向对象设计
分析是提取和整理用户需求,并建立问题域精确模型的过程。设计则是把分析阶段得到的需求转变成符合成本和质量要求的、抽象的系统实现方案的过程。
从面向对象分析到面向对象设计(OOD),是一个逐渐扩充模型的过程。或者说,面向对象设计就是用面向对象观点建立求解域模型的过程。
本章首先讲述为获得优秀设计结果应该遵循的准则,然后具体讲述面向对象设计的任务和方法。
2.1 面向对象设计的准则
(1)模块化 (2)抽象 (3)信息隐藏 (4)弱耦合 (5)强内聚 (6)可重用
(1)模块化
对象就是模块
把数据结构和操作这些数据的方法
紧密地结合在一起
(2)抽象
过程抽象
数据抽象:类
参数化抽象:C++的“模板”
(3)信息隐藏
通过对象的封装性实现
类分离了接口与实现,支持信息隐藏
(4)弱耦合
耦合:一个软件结构内不同模块之间互连的紧密程度
弱耦合:系统中某一部分的变化对其他部分的影响降到最低程度
对象之间的耦合:交互耦合&继承耦合
(5)强内聚
内聚衡量一个模块内各个元素彼此结合的紧密程度
在设计时应该力求做到高内聚
面向对象设计的3种内聚:
服务内聚、类内聚、一般\特殊内聚
(6)可重用
尽量使用已有的类
如果确实需要创建新类,则在设计这些新类的协议时,应该考虑将来的可重复使用性
2 面向对象设计
分析是提取和整理用户需求,并建立问题域精确模型的过程。设计则是把分析阶段得到的需求转变成符合成本和质量要求的、抽象的系统实现方案的过程。
从面向对象分析到面向对象设计(OOD),是一个逐渐扩充模型的过程。或者说,面向对象设计就是用面向对象观点建立求解域模型的过程。
本章首先讲述为获得优秀设计结果应该遵循的准则,然后具体讲述面向对象设计的任务和方法。
2.1 面向对象设计的准则
(1)模块化 (2)抽象 (3)信息隐藏 (4)弱耦合 (5)强内聚 (6)可重用
(1)模块化
对象就是模块
把数据结构和操作这些数据的方法
紧密地结合在一起
(2)抽象
过程抽象
数据抽象:类
参数化抽象:C++的“模板”
(3)信息隐藏
通过对象的封装性实现
类分离了接口与实现,支持信息隐藏
(4)弱耦合
耦合:一个软件结构内不同模块之间互连的紧密程度
弱耦合:系统中某一部分的变化对其他部分的影响降到最低程度
对象之间的耦合:交互耦合&继承耦合
(5)强内聚
内聚衡量一个模块内各个元素彼此结合的紧密程度
在设计时应该力求做到高内聚
面向对象设计的3种内聚:
服务内聚、类内聚、一般\特殊内聚
(6)可重用
尽量使用已有的类
如果确实需要创建新类,则在设计这些新类的协议时,应该考虑将来的可重复使用性
问题:为什么要软件重用,好处,软件重用概念
11.5设计问题域子系统
在面向对象设计过程中,可能对面向对象分析所得出的问题域模型做补充或修改
1. 调整需求 2. 重用已有的类 3. 把问题域类组合在一起 4. 添加一般化类以建立协议 5. 调整继承类层次
第十三章 软件项目管理
2.3.2 Gantt图
Gantt(甘特)图是历史悠久、应用广泛的制定进度计划的工具
下面通过一个非常简单的例子介绍这种工具
2.3.3 工程网络
Gantt图能很形象地描绘任务分解情况,以及每个子任务(作业)的开始时间和结束时间,因此是进度计划和进度管理的有力工具。它具有直观简明和容易掌握、容易绘制的优点,但是Gantt图也有3个主要缺点。
(1) 不能显式地描绘各项作业彼此间的依赖关系。
(2) 进度计划的关键部分不明确,难于判定哪些部分应当是主攻和主控的对象。
(3) 计划中有潜力的部分及潜力的大小不明确,往往造成潜力的浪费。
当把一个工程项目分解成许多子任务,并且它们彼此间的依赖关系又比较复杂时,仅仅用Gantt图作为安排进度的工具是不够的,不仅难于做出既节省资源又保证进度的计划,而且还容易发生差错。
工程网络是制定进度计划时另一种常用的图形工具,它同样能描绘任务分解情况以及每项作业的开始时间和结束时间,此外,它还显式地描绘各个作业彼此间的依赖关系。因此,工程网络是系统分析和系统设计的强有力的工具。
在工程网络中用箭头表示作业(例如,刮旧漆,刷新漆,清理等),用圆圈表示事件(一项作业开始或结束)。注意,事件仅仅是可以明确定义的时间点,它并不消耗时间和资源。作业通常既消耗资源又需要持续一定时间。下图是旧木板房刷漆工程的工程网络。图中表示刮第1面墙上旧漆的作业开始于事件1,结束于事件2。用开始事件和结束事件的编号标识一个作业,因此“刮第1面墙上旧漆”是作业1-2。
在下图中还有一些虚线箭头,它们表示虚拟作业,也就是事实上并不存在的作业。引入虚拟作业是为了显式地表示作业之间的依赖关系。