软件工程是研究和应用如何以【系统性的、规范化的、可定量的过程化方法】去【开发软件和维护软件】,以及如何【把经过时间考验而证明正确的管理技术和当前能够得到的最好的技术方法结合起来】的学科。
OOSE,即Object-Oriented Software Engineering,面向对象的软件工程。
OOA,即Object-Oriented Analysis,面向对象分析。
软件工程与计算机科学差别:
软件工程是应用【计算机科学、数学、工程科学与管理科学】等基本原理,开发软件的工程。它借鉴传统工程的原则和方法,以提高质量,降低成本为目的。其中:
1、计算机科学和数学用于构造软件的模型与算法;
2、工程科学用于制定规范、设计范型、评估成本及确定权衡;
3、管理科学用于计划、资源、质量、成本等管理。
面向对象程序设计语言三大特征:封装、继承和多态。其中:
1、封装是类将内部数据隐藏。封装为用户提供对象的属性和行为的接口,用户通过这些接口使用这些类,无须知道这些类内部是如何构成的,同时用户不能操作类中的内部数据。
2、继承允许程序员依据一个类来定义另一个类,相关名称有子类、父类、基类、派生类等。以C++为例,派生类可以访问基类中所有的非私有成员。基类成员如果不想被派生类的成员函数访问,则应在基类中声明为private。
3、多态即为接口的多种不同的实现方式。多态性是允许将父对象设置成为一个或更多的其他子对象相等的技术。在程序中定义的引用变量所指向的具体类型和通过该引用变量的方法调用在编程的时候并不确定,当处于运行期间才确定。即引用变量究竟指向哪一个实例对象,在编译期间是不确定的,只有运行期间才能确定,这样的话不用修改源码就可以把变量绑定到不同的类实例上,让程序拥有了多个运行状态,即多态。
软件有一个孕育、诞生、成长、成熟、衰亡的生存过程,这个过程即为软件的生命周期。软件的生命周期包括定义、开发和运行维护三个阶段,其中:
1、定义:包括问题定义、可行性分析、需求分析等。此阶段需要准确地解决软件系统必须做什么的问题。在软件生命周期的各个阶段中,需求分析出错对软件的影响最大;
2、开发:包括系统设计、程序设计、编码与模块测试、集成和系统测试等。软件开发包括需求分析、设计和实现三个重要阶段;
3、运行维护:包括交付与维护等。软件交付给用户之后并不意味着就退出了软件开发的生命周期。
软件项目可能失败的最重要的五个原因:
1、需求不完整;
2、缺少客户的参与;
3、缺少资源;
4、期望值过高;
5、缺少高层的支持。
需求分析的重要性有以下几点:
1、需求分析的准确与否是决定软件开发是否成功的一个关键因素;
2、需求分析可以帮助开发人员真正理解业务问题;
3、需求分析是估算成本和进度的基础;
4、需求分析可以避免建造错误的系统,从而减少不必要的浪费;
5、软件规格说明书有助于开发人员与客户在“系统应该做什么”问题上达成正式契约;
6、需求分析形成了软件开发的基线,有助于管理软件的演化和变更;
7、软件需求是软件质量的基础,为系统验收测试提供了标准。
软件需求还:
1、反映了用户解决问题或达到目标所需的条件或能力;
2、规定了系统或系统部件要满足合同、标准、规范或其它正式文档所需具有的条件或能力;
3、包括了可以反映上面1或2所描述的条件或能力的文档说明书。
软件需求的概念涵盖了用户角度(系统的外部行为)和开发人员角度(系统的内部特性)两个方面,其中的关键在于需求一定要文档化。下图描述了软件需求分析中的功能需求与非功能需求:
需求分析是软件开发工作的基础,其任务是确定软件系统的功能,需要准确回答软件必须做什么的问题,可将其概括为理解、分析、表达六个字,要求必须编写需求规格说明书。
需求分析的核心是建立分析模型,其中:
1、数据字典是分析模型的核心;
2、通过DFD(数据流图,Data Flow Diagram),建立系统的功能模型。功能建模的思想就是用抽象模型的概念,按照软件内部数据传递、变换的关系,自顶向下逐层分解,直到找到满足功能要求的所有可实现的软件为止;
3、通过E-R图(实体-联系图,Entity Relationship Diagram),建立系统的数据模型。数据模型包括三种互相关联的信息:数据对象、描述对象的属性、描述对象间相互连接的关系。具体绘制方法同数据库原理E-R模型画法(本文不会提及此内容);
4、通过STD(状态迁移图,State Transition Diagram),建立系统的行为模型。
其中,DFD和E-R图描述了系统的静态方面的信息,而STD描述了系统行为方面的信息。
数据流图也称为气泡图、泡泡图。数据流图:
1、可以表示任何一个(人工的、自动的、或混合的)系统中的数据流程;
2、每个表示加工的圆圈可能需要进一步分解以求得关于问题的全面理解;
3、 着重强调的是数据流程而不是控制流程。
DFD有四种类型的符号:
1、外部实体:表示系统之外信息的来源或去向。一般使用矩形表示:
2、加工处理:对输入系统的数据进行加工和处理。一般使用圆形或椭圆表示:
3、存储:为一个或多个转换提供数据源或数据存储服务的缓冲区、文件或数据库。一般使用两条线表示:
4、数据流:在转换之间有向流动的数据项或数据项集合。一般使用箭头表示:
举个例子,下图是某个教材采购与销售管理系统的数据流图:
关于分层数据流图,有:
1、对于复杂的实际问题,在数据流图上常常出现十几个甚至几十个加工。
2、画数据流图的基本步骤概括地说,就是自外向内,自顶向下,逐层细化,完善求精。
3、按照系统的层次结构进行逐步分解,并以分层的数据流图反映复杂的结构关系,这样能清楚地表达整个系统,同时可以使得整个系统容易被理解。
下面是分层数据流图的一个例子:
绘制分层数据流图时需要注意可读性、一致性、正确性:
1、数据流图上所有图形符号只限于前述四种基本图形元素。
2、顶层数据流图上的数据流必须封闭在外部实体之间。
3、数据应通过加工流动,避免从一个数据存储直接流向另一个数据存储。
4、每个加工至少有一个输入数据流和一个输出数据流,且输入与输出数据流要平衡。
5、在数据流图中,需按层给加工框编号。编号表明该加工处在哪一层,以及上下层的父图与子图的对应关系。
6、规定任何一个数据流子图必须与它上一层的一个加工对应,两者的输入数据流和输出数据流必须一致。
7、图上的每个元素都必须有名字。数据流和数据文件的名字应当是“名词”或“名词性短语”,表明流动的数据是什么。加工的名字应当是“动词+宾语”,表明做什么事情。
8、可以在数据流图中加入物质流,帮助用户理解数据流图。
9、数据流图中不可夹带控制流。
10、第一次画时可以忽略琐碎的细节,以集中精力于主要数据流。
下图是教材采购与销售管理系统二层数据流图L2.1:
下图是教材采购与销售管理系统二层数据流图L2.2:
数据字典用于精确、严格地定义每一个与系统相关的数据元素(包括数据流、数据存储和数据项),并以字典式顺序将它们组织起来,使得用户和分析员对系统中的每个数据元素有相同的理解。在数据字典的每一个词条中应包含以下信息:
1、名称:数据对象或控制项、数据存储或外部实体的名字。
2、别名或编号。
3、分类:属于这些类别的哪一种:数据对象?加工?数据流?数据文件?外部实体?控制项(事件/状态)?
4、描述:描述内容或数据结构等。
5、何处使用:使用该词条(数据或控制项)的加工。
6、注释:数据量、峰值、限制和组织方式等。
1、类型:数据流条目;
2、名字:购书列表;
3、别名:购书单列表;
4、描述:对学生提供的购书单通过查库存将有库存的购书信息汇总形成的列表;
5、定义:购书列表={需书单位+书名+(刊号)+数量+(时限)+[学生用书|教师用书|图书馆用书]}。
示例2:
1、类型:数据项条目;
2、名字:需书单位;
3、别名:购书单位;
4、描述:提供购书单的单位名称;
5、定义:20个汉字。
示例3:
1、类型:数据存储条目;
2、编号:F1;
3、名字:教材库存量表;
4、描述:记录每种教材的库存数量;
5、定义:教材库存量表={书名+(刊号)+(版本)+数量};
6、数据组织方式:按书名拼音顺序排列。
加工规格说明书:
1、说明了DFD中的数据加工的加工细节、数据加工的输入、实现加工的算法以及产生的输出;
2、指明了加工(功能)的约束和限制、与加工相关的性能要求以及影响加工的实现方式的设计约束;
3、用于撰写加工规格说明书的工具有结构化语言、判定表和判定树。
结构化语言的示例如下:
判定树的示例如下:
判定表的示例如下:
较早的软件开发使用的是结构程序设计方法,其定律是:
程序=算法+数据结构
即过程(函数)是一个独立的整体,数据结构(包含数据类型与数据)也是一个独立的整体。两者分开设计,以算法(函数或过程)为主。
结构化程序设计是一种面向过程的自顶向下的程序设计方法。结构化设计中模块和模块之间的关系被紧紧局限于信息流,试图通过信息流及其转换来认识系统,这限制了对模块之间众多关系的表达和体现,如继承、依赖。
流水线式的过程处理与人们日常处理问题的方式不一致。随着时间流逝,软件工程师越来越注重系统整体关系的表示和数据模型技术,并把数据结构与过程看作一个独立功能模块。于是程序定律被重新认识:
程序=过程+数据结构
上述思想符合现实世界中的事物特征,因为现实世界中区分事务主要依靠的就是事物各式各样的特征,包括事物不同的属性和特定的行为。于是集成化的软件开发方法——面向对象方法产生。在面向对象中,过程与数据结构被捆绑成一个对象,这样就不用为如何实现通盘的程序功能而费尽心机了。这时候,程序定义变为:
1、对象=过程+数据结构;
2、程序=对象+对象+…。
即程序就是许多对象在计算机中相继表现自己,而每个对象又单独是一个程序实体。
分析的过程是提取系统需求的过程。分析工作包括三个内容:
1、理解需求;
2、表达需求;
3、验证需求。
分析过程中最重要的文档资料是软件需求规格说明书,在面向对象中主要由功能模型、动态模型和对象模型三个部分组成,其中对象模型是核心。
OOA(Object-Oriented Analysis,面向对象分析)的关键是识别出问题域内的类与对象,并分析它们相互间的关系,最终建立起问题域的简洁、精确、可理解的正确模型。
OOA的目的是建立需求模型,在这个过程中,相关领域知识非常关键。
OOA就是抽取和整理用户需求并建立问题域精确模型的过程,过程中需要分析并陈述需求、用模型表示需求以及建立系统的分析模型。注意:分析人员必须向领域专家学习,特别要正确认识继承关系,其建立是知识的抽取过程。
需求的3个子模型:
1、对象模型(静态结构,类与关联);
2、动态模型(交互次序,顺序图与状态图);
3、功能模型(数据变换,用例)。
复杂问题(大型系统)的对象模型通常由5个层次组成:
1、主题层;
2、类与对象层;
3、结构层;
4、属性层;
5、服务层。
主题是指导读者理解大型、复杂模型的一种机制。通过划分主题,把一个大型、复杂的对象模型分解成几个不同的的概念范畴。
面向对象分析(OOA,Object-Oriented Analysis)的过程:
1、寻找类与对象;
2、识别主题;
3、定义属性;
4、定义服务,建立动态模型与功能模型。
需求陈述的内容有:
1、问题范围;
2、功能需求;
3、性能需求;
4、应用环境;
5、假设条件。
注意事项如下:
1、语法正确:慎重选用名词、动词、形容词和同义词;
2、把需求与设计决策区别开;
3、可简可繁;
4、并非一陈不变,而是随着认识的深入不断地完善;
5、与领域专家密切配合,共同提炼整理需求;
6、必要时可先建立原型系统。
下图是某银行开发一个自动取款机系统的示例:
该系统由ATM、中央计算机、分行计算机、柜员终端组成,其中:
1、柜员通过柜员终端处理储户提交的储蓄事务。储户可以开户、存款、取款,同时柜员提供相应的服务;
2、储户可领取现金兑换卡,使用该卡通过ATM可完成提取现金的操作;
3、系统应该能处理并发,如一张卡可访问储户的若干个账户,并非全部账户,而且一张卡可以有多个副本;
4、ATM的事务处理:用户输入密码→中行→委托分行验证→通过认证提供事务服务。
对象模型描述了现实世界中“类与对象”及其之间的关系,表示了目标系统的静态数据结构。需求陈述、应用领域的专业知识以及关于客观世界的常识是建立对象模型的主要信息来源。
OOA中对象模型常使用UML中的类图进行建模。建立对象模型的工作步骤(共5步)如下:
1、确定类和关联:①找出所有候选的类和对象;②筛选掉不正确的或不必要的类或对象;
2、大型系统要进一步划分为若干个主题,如ATM系统可分为总行、分行、ATM共三个主题;
3、(1)为类和关联添加属性,包括分析和选择属性:
(2)利用继承关系进一步合并和组织类,下面是两种建立泛化关系的方式:
4、确定类的操作,建立动态模型和功能模型;
5、反复修改。如针对ATM系统而言,将“现金兑换卡”类分解为“卡权限”和“现金兑换卡”两个类;事务由“更新”组成;把“总行”与“中央计算机”合并,“分行”与“分行计算机”合并。
在第一步中,关于找出候选的类与对象,有两种方法:
1、分类法:对客观事物的分类,如:
2、非正式分析法:
举个例子,下面是ATM系统的非正式分析中需求陈述中的名词(共34个):
银行、ATM、系统、中央计算机、分行计算机、柜员终端、网络、总行、分行、软件、成本、市、街道、营业厅、储蓄所、柜员、储户、现金、支票、账户、事务、现金兑换卡、余额、磁卡、分行代码、卡号、用户、副本、信息、密码、类型、取款额、账单、访问。
除此之外,ATM系统中隐含的名词是通信链路与事务日志。为了筛选出正确的类与对象,下面列出筛选依据:
1、若两个类表达的是同样的信息,此时保留最富于描述力的名称。例如在【储户与用户】、【现金兑换卡、副本和磁卡】这五个词中,只保留储户与现金兑换卡两个词;
2、将与系统无关的词去掉,仅保留那些与本系统密切相关的词。例如ATM系统中不考虑成本、ATM及柜员终端放置的地点,应去掉:成本、市、街道、营业厅、储蓄所;
3、去掉概念笼统的词。如银行、访问(指事务)、信息(用户名密码)、网络、系统、软件;
4、一些名词描述的是对象的属性,也应去掉。如现金、支票、取款额、账单、余额、分行代码、卡号、密码、类型;
5、对于既可以做名词又可做动词的词或词组,需要考虑是该作为类还是类的操作。原则上,本身具有属性需独立存在的操作,应该作为类与对象。
6、在分析阶段中不应过早地考虑怎样实现目标,去掉仅和实现有关的候选类与对象即可。如需要去掉ATM中的通信链路、事务日志(应在设计时考虑)。
通过上面的6种筛选依据,ATM系统最终的类是:ATM、中央计算机、分行计算机、柜员终端、总行、分行、柜员、储户、账户、事务、现金兑换卡(确确实实是这样呢)。
数据模型包括三种互相关联的信息:数据对象、描述对象的属性、描述对象间相互连接的关系。确定关联的步骤为以下两步:
1、初步确定关联。需求陈述中使用的描述性名词或动词词组,通常表示关联关系。除此之外还要发现一些隐含的关联,并且补充关联。可与领域专家讨论问题域实体间的相互依赖、相互作用关系;
2、筛选。
举个例子,下面是对ATM系统进行关联识别,直接提取动词短语得出的关联(共18个,有横线的是删去的关联):
1、ATM、中央计算机、分行计算机及柜员终端组成网络 ;
2、总行拥有多台ATM(总行拥有中央计算机,ATM与中央计算机通信);
3、ATM设在主要街道上 ;
4、分行提供分行计算机和柜员终端;
5、分行分摊软件园开发成本 ;
6、储户拥有账户;
7、分行计算机处理针对账户的事务(可分解为分行计算机处理事务、事务修改账户两个关联);
8、分行计算机维护账户(分行保管账户、事务修改账户);
9、柜员终端与分行计算机通信;
10、柜员终端设在分行营业厅及储蓄所内 ;
11、柜员输入针对账户的事务,分解为柜员输入事务,事务修改账户两个关联;
12、ATM与中央计算机交换关于事务的信息,分解为ATM与中央计算机通信,在ATM上输入事务两个关联;
13、中央计算机确定事务与分行的对应关系,中央计算机与分行通信;
14、ATM读现金兑换卡 ;
15、ATM与用户交互 ;
16、ATM吐出现金 ;
17、ATM打印账单 ;
18、系统处理并发的访问 。
下面是需求陈述中隐含的关联(共6个,有横线的是删去的关联):
1、总行由各个分行组成;
2、分行保管账户;
3、总行拥有中央计算机;
4、系统维护事务日志 ;
5、系统提供必要的安全性 ;
6、储户拥有现金兑换卡。
下面是根据问题域得出的关联(共2个):
1、现金兑换卡访问账户;
2、分行雇用柜员。
下面是将关联筛选掉的依据(共5个):
1、已删去的类之间的关联;
2、与问题无关的或应在实现阶段考虑的关联;
3、需要删去瞬时事件,因为关联应描述问题域的静态结构,而不是一个瞬时事件(如ATM读现金兑换卡,ATM与用户交互)。隐含结构应重新表示(如应将中央计算机与分行的对应关系改为与分行通信)。
4、将三元关联分解为二元关联或受限关联;
5、去掉派生关联,即去掉那些可以用其它关联表示的关联。
通过以下四种方式进一步完善关联:
1、正名;
2、分解:如ATM系统中的事务分解为远程事务和柜员事务等;
3、补充:如ATM系统中的柜员输入柜员事务、柜员事务输进柜员终端、在ATM上输入远程事务、远程事务由现金兑换卡授权等;
4、标明重数。
建立动态模型的步骤(共3步):
1、编写典型交互行为的脚本;
2、提取脚本中的事件;
3、利用UML中的顺序图和状态图建立动态模型。
脚本原意为“拍摄电影等所依据的本子,里面记载台词、故事情节”。在动态模型中,脚本指系统在某一执行期间内出现的一系列事件。在用例模型中,脚本指用例的实例,表示系统的一次具体执行过程。编写脚本时,应先编写正常情况的脚本,再考虑特殊情况的,最后考虑出错情况的脚本。
示例一,ATM系统的正常情况脚本:
1、ATM请储户插卡:储户插入一张现金兑换卡;
2、ATM接受该卡并读它上面的分行代码和卡号;
3、ATM要求储户输入密码:储户输入自己的密码;
4、ATM请求总行验证卡号和密码:总行要求分行核对储户密码,然后通知ATM说这张卡有效;
5、ATM要求储户选择事务类型(取款、转账、查询等):储户选择“取款”;
6、ATM要求储户输入取款额:储户输入880;
7、ATM确认取款额。在预先规定的限额内要求总行处理这个事务;总行把请求转给分行,该分行成功地处理完这项事务并返回该账户的新余额;
8、ATM吐出现金并请储户拿走这些现金:储户拿走现金;
9、ATM问储户是否继续办理事务:储户回答“不”;
10、ATM打印账单,退出现金兑换卡,请储户拿走它们:储户取走账单和卡;
11、ATM请储户插卡。
示例二,ATM系统的异常情况脚本:
1、ATM请储户插卡:储户插入一张现金兑换卡;
2、ATM接受这张卡并顺序读它上面的数字;
3、ATM要求密码:储户误输入8888;
4、ATM请求总行验证输入的数字和密码:总行在向有关分行咨询之后拒绝这张卡;
5、ATM显示“密码错”,并请储户重新输入密码:储户输入1234;ATM请总行验证后知道这次输入的密码正确;
6、ATM请储户选择事务类型:储户选择“取款”;
7、ATM询问取款额:储户改变主意不想取款了,他按下“取消”键;
8、ATM退出现金兑换卡,并请储户拿走它:储户拿走他的卡;
9、ATM请储户插卡。
课件未给出详细内容。
定义服务:
1、识别常规行为;
2、从事件中导出操作(顺序图、状态图);
3、从功能模型中提取操作;
4、利用继承减少冗余操作;
5、反复审查。
END