需求分析的本质是对收集到的需求进行提炼、分析和审查,为最终用户所看到的系统建立概念化的分析模型,即把客户现实需求进行抽象、映射和转换,以形成软件需求模型,如图3.4所示。
图3.4 从客户现实需求到软件需求模型
需求分析的目标是对产品及其环境的交互进行更深入的了解,识别系统需求,设计软件体系结构,建立需求与体系结构组件间的关联,在体系结构设计实现过程中进一步识别矛盾冲突,并通过干系人之间的协调磋商解决问题。其实质是概念建模,即选择常用的建模语言,进行功能建模和信息建模。关键问题是实现体系结构设计与需求分配。可以通过评估需求的满足度来评价体系结构设计的质量。
需求分析建模的一般步骤是:首先分析需求可行性,再细化需求,最后建立需求分析模型,包括明确功能活动、分析问题类和类之间的关系、确定系统和类行为、数据流等方面的内容。
通过需求分析,能描述客户需要什么(软件的信息、功能和行为),为软件设计奠定基础(结构、接口、构件设计),定义在软件完成后可以被确认的一组需求。需求分析是一项重要的工作,也是最困难的工作。该阶段的工作有以下特点。
●用户与开发人员很难进行交流。在软件生命周期中,其他阶段都是面向软件技术问题的,只有本阶段是面向用户的。需求分析是对用户的业务活动进行分析,明确在用户的业务环境中软件系统应该做什么。但是在开始时,开发人员和用户双方都不能准确提出系统要做什么,因为软件开发人员不是用户问题领域的专家,不熟悉用户的业务活动和业务环境,而用户也不熟悉计算机应用的有关问题。由于双方互相不了解对方的工作,又缺乏共同语言,因此在交流时存在隔阂。
●用户的需求是动态变化的。对于一个大型而复杂的软件系统,用户很难精确、完整地提出针对这个软件系统的功能和性能要求。开始只能提出一个大概、模糊的功能,只有经过长时间的反复认识才能逐步明确。有时进入设计、编程阶段才能明确,甚至到开发后期还在提新的要求。这无疑给软件开发带来很多困难。
●系统变更的代价呈非线性增长。需求分析是软件开发的基础。假定在该阶段发现一个错误,解决它需要用一小时的时间,而到设计、编程、测试和维护阶段解决该错误可能要花2.5倍、5倍、25倍甚至100倍的时间。因而做好需求分析是更为经济的选择。
因此,对于大型复杂系统而言,开发人员需要对用户的需求及现实环境进行充分的调查和了解,从技术、经济和社会因素三个方面进行研究并论证该软件项目的可行性,根据可行性研究的结果,决定项目的取舍。
需求分析的经验原则是:模型抽象级别应该高一些,不要陷入细节;模型的每个元素应该能增加对需求的整体理解;有关基础结构和非功能的模型应推延到设计阶段;最小化系统内关联;确认模型对客户、设计人员、测试人员都有价值;尽可能保持模型简洁。
需求分析的基本思想有四点:①抽象,即透过现象看本质,抓住事物的本质,捕获问题空间的“一般/特殊”关系,这是认识、构造问题的一般途径;②划分,即分而治之,分离问题,捕获问题空间的“整体/部分”关系是降低问题复杂性的基本途径;③投影,即从不同的视角看问题,捕获并建立问题空间的多维视图是描述问题的基本手段;④建模,即采用规范的描述方法,将模糊的、不确定的用户需求表达为清晰的、严格的模型,作为后续设计与实现的基础。
需求分析的任务有以下四点。
●确定对系统的综合需求。通常对软件系统有几方面的综合需求:功能需求、性能需求、可靠性和可用性需求、出错处理需求、接口需求、约束需求、逆向需求、将来可能提出的需求。
●分析系统的数据要求。任何一个软件本质上都是信息处理系统,系统必须处理的信息和系统应该产生的信息在很大程度上决定了系统的面貌,对软件设计有深远的影响。因此必须分析系统的数据要求,这是需求分析的一项重要任务。分析系统的数据要求通常采用建立数据模型的方法。复杂的数据由许多基本的数据元素组成,数据结构表示数据元素之间的逻辑关系。利用数据字典可以全面定义数据,但是数据字典的缺点是不够直观。为了提高可理解性,通常利用图形化工具(如方框图)辅助描述数据结构。
●导出系统的逻辑模型。综合上述两项分析的结果可以导出系统的详细逻辑模型,通常用数据流图、E-R图、状态转换图、数据字典和主要的处理算法描述这个逻辑模型。该模型有助于增强对需求的理解,通过模型能够检测到需求中的不一致性、模糊性、错误和遗漏,并使项目的参与者之间能够开展高效的交流。目前有两种模型形态,即形式化的数学模型和非形式化的图形模型。
●修正系统开发计划。根据在分析过程中获得的对系统更深入的了解,可以比较准确地估计系统的成本和进度,修正以前定制的开发计划。
现有的需求分析方法主要有两种,即结构化分析方法、面向对象分析方法,具体内容将在3.4.2节和3.4.3节中介绍。
作为一种“思想”工具,结构化分析方法可以用于:定义需求,建立待建系统的功能模型;定义满足需求的结构,给出一种特定的软件解决方案。
在软件工程中,一般认为数据是客观事物的一种表示,而信息是具有特定语义的数据,同时可以将数据看作信息的载体。所谓数据流是指数据的流动,通常用一组线和箭头代表数据流动的起始、指向等。数据加工是对数据进行变换的单元,它代表了一组对数据的操作;数据存储则是一种数据的静态结构,比如文件、数据库的元素等。另外,数据源和数据潭是系统外的实体,不属于本系统,数据源通俗来讲是系统的输入,而数据潭即系统的输出。
数据流图(Data Flow Diagram,DFD)用于描绘数据在系统中各个逻辑功能模块之间的流动和处理过程,是功能模型,主要刻画功能的输入和输出数据、数据的源头和目的地。
对于DFD中出现的所有被命名的图形元素(数据流、数据项、数据存储、加工)在数据字典(Data Dictionary,DD)中作为一个词条加以定义,并具有顺序、选择或重复结构,规定了子界,使每一个图形元素的名字都有一个确切的解释,并且所有的定义都是严密的、精确的,不可有含混、二义性。
例如,用户输入 a 、 b 、 c 、 d 四个值,系统计算( a + b )*( c + a * d ),并将结果输出到一个文件中存储,这个过程可以表示为如图3.5所示的DFD。
图3.5 DFD示意图
另外还有常用的数据建模-实体联系图(E-R图)把用户的数据要求清楚、准确地描述出来,建立一个概念性的数据模型,包含数据实体、主要属性和关联关系。图3.6所示为一个教师、学生、课程的E-R图。其中,实体的抽取是需求分析的重难点,可以考虑使用分析工具来自动抽取。关系的表达可以是一对一或一对多,也分必选项或可选项,需要根据实际情况灵活加以判断。
图3.6 E-R图示意
面向对象需求分析是使用面向对象模型分析软件需求的一种方法。面向对象模型包含静态结构(对象模型)、交互次序(动态模型)和系统功能(功能模型)。面向对象需求分析通常有以下内容:寻找类与对象、识别结构、识别主题、定义属性、建立动态模型、建立功能模型、定义服务。
先介绍一些基本概念。对象就是一个包含数据以及与这些数据有关的操作的集合,每个实体都是一个对象。类是一组具有相同数据结构和相同操作的对象集合,类的定义包括一组数据属性和在数据上的一组合法操作。类定义可视为一个具有类似特性与共同行为的对象模板,可用来产生对象。类是对象的抽象,而对象是类的具体实例。对象之间有消息传递。继承是在一个已存在的类的基础上建立一个新的类,将已存在的类称为基类或父类,将新建立的类称为派生类或子类。
有些对象具有相同的结构和特性,如计算机专业编号0022、9922是两个不同的对象,但属于同一类型,具有完全相同的结构和特性。简而言之,面向对象=对象+类+继承+消息。
每个对象都属于一个类型。大家知道,在C++中对象的类型就称为类(class),类代表某一批对象的共性和特征。大家在学习C++时,先声明一个类(类型),然后用它去定义若干个同类型的对象,那么对象就是一个类(类型)的变量。例如,先声明了“首都”这样一个类,那么北京、东京、莫斯科则都属于“首都”类的对象。所以说,类是用来定义对象的一种抽象数据类型,或者说,类是产生对象的模板。
面向对象技术强调软件的可重用性(复用)。在C++中,可重用性是通过“继承”这一机制来实现的。继承是面向对象技术中的一个重要组成部分。继承使软件的重用成为可能。过去软件开发人员开发新的软件时,从已有的软件中直接选用完全符合要求的部件的情况并不多,一般都要进行许多修改才能使用,因此工作量很大。继承机制很好地解决了这个问题。另外,以已有的类为基础生成一些派生类(子类),在子类中保存父类中有用的数据和操作,去掉不需要的部分。新生成的子类还可以再生成孙类,而且一个子类可以从多个父类中获得继承,这就是多继承机制。
为了理解面向对象的概念,我们看一个现实世界中对象的例子。比如椅子是家具(furniture)类中的一个成员(也称为“实例”)。一组类属性与类中的每个对象关联。家具有很多属性,比如价格、尺寸等。无论是椅子还是桌子、沙发或衣橱等这些现实世界中的对象,都具有这些属性。一旦类被定义,当新的类的实例被创建时,属性就可以被复用。例如,我们定义一个新的称为chable(即在椅子和桌子之间的东西)的对象,它也是类furniture的成员,这就意味着chable继承furniture的所有属性。
虽然通过描述类的属性给出了对象的定义,但是在类furniture中的每个对象可以被一系列不同的方式操纵,如:被定义买和卖、物理地被修改;在桌子涂上新的油漆;椅子从一个地方移动到另一个地方;等等。这些操作被称为“服务”或“方法”,它将修改对象的一个属性或多个属性。例如,位置(location)属性是一个数据项,定义如下:位置=大厦+楼层+房号。被命名为move(移动)的操作将修改构成属性位置的一个或多个数据项(大厦、楼层或房号)。为了完成操作,“移动”必须“知道”这些数据项。操作“移动”可用于桌子或椅子,只要二者是类furniture的实例,所有对类furniture的合法操作(如买、卖、重量)将被“联结”到对象定义中,并且被类的所有实例继承。
面向对象分析(OOA)的核心思想是利用面向对象(OO)的概念和方法对软件需求建造模型,以使用户需求逐步精确化、一致化、完全化。为此,OOA的方法步骤为:首先识别对象(找出分析过程中的所有名词或名词短语,合并同义词,需要除去有动作含义的名词,因为它们将被描述为对象的操作),包括其属性及外部服务;进而识别类及其结构,包括定义对象之间的消息传递。
标识潜在对象有以下几种可能:与目标系统交换信息的外部实体,如物理设备、操作人员或用户、其他有关的子系统;事物,如报告、文字、信号、报表、显示信息,它们是问题信息域的一部分;位置,如制造场所或装载码头,是建立问题的系统整体功能的环境;组织机构,如单位、小组;事件,目标系统运行过程中可能出现并需要系统记忆的事件,如核电站运转时的意外事故;角色,与目标系统发生交互作用的人员所扮演的各种角色,如管理人员、工程师、销售人员等;聚焦对象,用于表示一组成分的对象,如物理设备。
筛选对象的规则如下:对象应具有记忆自身状态的能力,即潜在对象的信息必须被记住才可能使系统工作;对象应具有有意义的操作,以便可以通过某种方式来修改对象的属性值;对象应具有多种意义的属性,因为在分析阶段,分析的关注点应该是较大的信息,即具有多个属性值的对象;公共属性,可以为潜在对象定义一组属性,这些属性适用于对象每一次发生的事件;公共操作,可以为潜在对象定义一组操作,这些操作适用于对象每一次发生的事件;必须的需求,对象应是软件需求模型的必要成分,与设计和实现无关。
面向对象需求分析与建模通常分为三类模型:领域模型、交互模型和状态模型。首先需要领域建模,寻找概念类,进而通过顺序图和协作图等动态模型来刻画使用场景,再通过一系列的状态模型来表达需求。
第一阶段:建立静态模型(领域建模),从用例模型入手,寻找概念类,进而细化概念类,识别边界类、控制类和实体类,添加关联和属性。其中,寻找概念类可以重用或修改现有的模型,包括参考已有系统或书籍资料等,或者使用分类列表,如业务交易、交易项目、角色、地点、记录、物理对象等,或者通过分析用例文本确定名词短语。
第二阶段:建立动态模型,从用例和活动图入手,建立系统顺序图和协作图,建立分析对象的顺序图,以确定分析类的操作。建立动态模型的过程示意图如图3.7所示。
图3.7 建立动态模型的过程示意