2.5 面向对象分析方法*
面向对象分析方法的基本思想是从现实世界中客观存在的事物出发来构造软件,并在系统构造中尽可能地运用人类的自然思维方式。开发一个软件是为了解决某些问题,这些问题涉及的业务范围称为该软件的问题域。面向对象强调以问题域中的事物为中心来思考问题、认识问题,并根据这些事物的本质特征,把它抽象地表示为系统中的对象,作为系统的基本构成单位。因此,面向对象方法可以使系统直接地映射问题域,保持问题域中事物及其相互关系的本来面貌。
2.5.1 面向对象分析方法概述
面向对象分析方法的形成最初是从面向对象程序设计语言开始的,随之逐步形成面向对象的分析和设计方法。创始的面向对象程序设计语言是 20世纪60年代的Simula 67语言。它是一种通用的仿真建模语言,其中对象的概念和方法,启示了人们在软件设计方面的新思维。各种面向对象程序设计语言的出现直接导致了面向对象的广泛应用,面向对象技术也很快被应用于系统分析和系统设计。20世纪80年代末以来,面向对象技术成为研究的热点,出现了几十种支持软件开发的面向对象方法。其中,比较有代表性的方法有1986年Booch提出的面向对象分析与设计方法论(OOA/OOD)、1991年Rumbaugh提出的面向对象模型技术(OMT)、1994年Jacobson提出的面向对象软件工程方法学(OOSE)。
经过一段时间的探索,Booch、Rumbaugh和Jacobson将他们各自的对象建模方法结合到一起,提出了统一建模语言(Unified Modeling Language,UML),该方法结合各个方法的优点,统一了符号体系,并从其他的方法和工程实践中吸收了许多经过实际检验的概念和技术。经过几年的发展,UML已经成为面向对象方法的公认标准。
面向对象软件开发方法的一般思路是首先获取需求,用文字说明、图形、表格等建立描述客观世界的抽象模型,识别与问题有关的类与类之间的联系,加上与实现环境有关的类(如界面等),逐步细化模型;经过设计的类与联系调整后,完成整个系统的描述,然后对类进行编码和测试,得到结果。该方法具有以下主要特点:
(1)从问题域中客观存在的事物出发来构造软件系统,用对象作为对这些事物的抽象表示,并以此作为系统的基本构成单位。
(2)事物的静态特征(可以用一些数据来表达的特征)用对象的属性来表示,事物的动态特征(事物的行为)用对象的操作来表示。
(3)对象的属性与操作结合为一体,成为一个独立的实体,对外屏蔽其内部细节(称为封装)。
(4)对事物进行分类,把具有相同属性和相同操作的对象归为一类,类是这些对象的抽象描述,每个对象是其类的一个实例。
(5)通过在不同程度上运用抽象原则(忽略事物之间的一些差异),可以得到较一般和较特殊的类。特殊类继承一般类的属性和操作,面向对象方法支持这种继承关系的描述与实现,从而简化系统的构造过程及其文档。
(6)复杂对象可以用简单的对象作为其构成部分(称为聚合)。
(7)对象之间通过消息进行通信,以实现对象之间的动态联系。
(8)通过关联表达对象之间的静态关系。
2.5.2 面向对象建模
为了更好地理解问题,人们常常采用建立问题域模型的方法。模型就是为了理解事物而对事物做出的一种抽象,是对事物的一种可视化的描述。模型可以帮助人们思考问题,定义术语,在选择术语时做出适当的假设,并且帮助人们保持定义和假设的一致性。建立模型主要是为了减少复杂性。因为当面对大量模糊的、涉及众多专业领域的、错综复杂的信息时,开发人员往往感到无从下手。模型提供了组织大量信息的一种有效机制,为了开发复杂的软件系统,开发人员需要从不同的角度抽象出目标系统的特性,使用精确的表示方法构造系统模型,验证模型是否满足用户对目标系统的需求,并在设计过程中逐渐把和实现有关的细节加入模型,直至最终用程序实现模型。
采用面向对象方法开发软件,通常需要建立几种形式的模型,主要包括用例模型、概念模型、设计模型、配置模型、实现模型、测试模型等。使用用例驱动的开发方法是通过建立用况模型,再以用例模型为核心构造一系列模型,各个模型之间的关系如图2.22所示。
(1)用例模型包含所有用例及其与用户的关系。
(2)对象模型包含问题域涉及的类及其属性和关系,其作用是更详细地提炼用例,将系统的行为初步分配给提供行为的一组对象。
(3)设计模型将系统的静态结构定义为子系统、类和接口,并定义由子系统、类和接口之间的协作来实现的用例。
(4)实现模型包含构件和类到构件的映射。
(5)配置模型定义计算机的物理节点和构件到这些节点的映射。
(6)测试模型描述用于验证用例的测试用例。
图2.22 使用用例开发方法的一系列模型
所有这些模型都是相关的,只是每种模型的侧重点不同,它们合起来表示整个系统。在分析过程中,构造出完全独立于实现的分析模型;在设计阶段,则把求解域的结构逐步加入模型;在实现中把问题域和求解域的结构都编成程序代码,并进行严格的测试验证。
2.5.3 面向对象分析
面向对象分析的目标是完成对所解问题的分析,解决待建系统要做什么的问题,并建立系统的模型,为达到这一目标,必须完成以下任务:
(1)通过与用户沟通,了解用户的基本需求。
(2)从用户的角度认识系统,建立用例模型。
(3)以基本需求为指南,识别对象和类,包括定义其属性和操作。
(4)刻画类的层次结构。
(5)标识类(对象)之间的关系。
(6)识别对象的行为和系统的工作过程。
(7)递进地重复任务(1)~(6),直至完成模型建立。
任务(2)~(5)刻画了待建系统的静态结构(概念模型),任务(6)刻画了系统的动态行为(动态模型)。
一般面向对象分析可以从理解系统的使用方式开始,如果系统是人机交互的,则考虑被人使用的方式;如果系统涉及过程控制,则考虑被机器使用的方式;如果系统协同并控制应用程序,则考虑应用程序的使用方式。
1.获取用户需求
获取用户需求需要开发人员与用户充分交流,人们常常使用用例来收集用户的需求。首先找出使用该系统的不同执行者,这些执行者代表使用系统的不同角色。每个执行者可以叙述他如何使用系统,或者说明他需要系统提供什么功能,执行者提出的每个功能都是系统的一个用例。
一个用例描述了系统的一种用法或一个功能,所有执行者提出的所有用例就构成了系统的功能需求。开发人员根据用户提出的需求,建立用况模型,作为双方认识系统和开发系统的基础。
2.标识对象和类
在确定了系统的所有用例后,即可开始识别问题域中的对象和类。标识系统中的对象可以从问题域或用例描述着手,标识类和标识对象是一致的。把具有相同属性和操作的对象定义成一个类,为了对类有进一步认识,需要识别属性和操作。从本质上讲,属性定义了对象,它们表明了对象的基本特征,即为了完成用户规定的目标必须保存的信息。操作定义了对象的行为,并以某种方式修改对象的属性值。对操作的识别可通过对系统的过程描述分析、提取出来,通常把过程描述中的动词作为候选操作。
3.定义类的层次结构
在确定系统的类后,就可以识别类的层次结构。类之间的关系包括泛化、聚合、关联3种。泛化关系反映了类之间的一般与特殊的关系,如交通工具可以分为汽车、飞机、轮船等。交通工具类就是一个一般类,汽车、飞机、轮船则是特殊类。一般与特殊之间是一种“is a”的关系,如飞机是一种交通工具。汽车类还可以继续划分为轿车、货车等类,这样可形成类的层次结构。聚合关系反映了类之间整体与部分的关系,如学校由教师、学生、教学设备、后勤服务等部分组成。整体与部分关系是一种“has a”的关系,如学校有教师。同样整体与部分结构也具有层次结构。关联关系反映类之间直接联系的关系。例如,流水线生产是由各类部件装配车间共同构成的,上一个车间的产品是下一个车间的材料。即一个类的实例必须要用另一个类的实例才能完成工作。
4.建立对象(概念)模型
在明确了对象、类、属性、操作及类的层次结构之后,进一步识别对象、类之间的关联关系,就可以建立系统的对象(概念)模型。对象模型描述了系统的静态组成和结构,同时也是认识系统动态特性的基础。
对象行为模型描述了系统的动态机制,它指明系统如何响应外部事件或操作。建立动态模型的步骤如下:
(1)分析所有用例,理解系统中的交互行为。
(2)标识驱动交互序列的事件,理解这些事件如何与特定的对象相关联。
(3)为系统建立交互模型。
(4)分析对象的生存周期,为主要对象建立状态图。
(5)评审动态模型,以验证其准确性与一致性。
2.5.4 用例模型
用例模型主要由用例、用例描述和用例图组成,用来描述系统的外部特征。它表示从系统外部用户(执行者或角色)的观点看系统应该具备什么功能,因此它只需要说明系统实现什么功能,而不必说明如何实现该功能。一幅用例图包含的模型元素有系统、执行者、用例及用例之间的关系,如图2.23所示。
图2.23 用例图表示法
从图2.23可以看出系统被看成一个提供用例的黑盒子,其内部如何工作、用例如何实现,这些对于建立用况模型来说都不用考虑。代表系统的方框的边线表示系统边界,用于划定系统的功能范围。所有用例都在系统边界内,表明它们属于一个系统。角色则放在系统边界外部,表明角色是系统的外部执行者,但角色负责直接(或间接)驱动与之关联的用例的执行。
1.执行者
执行者是指与系统交互的人或其他系统,它代表外部实体。使用用例并且与系统交互的任何人或事物都是执行者,它在UML中常以一个稻草人图符来表示。执行者代表一种角色,而不是某个具体的人或物,角色由用户承担,但它不等同于用户。例如,在银行取款系统中,使用ATM的取款人是执行者。在一个具体的取款过程中,既可以是张三,也可以是李四,但不能把张三、李四这样的个体称为执行者。事实上,一个具体的人可以充当多种不同的角色。例如,某个人既可以是取款人,也可以是银行的工作人员,负责处理取款业务等。不仅如此,角色还可以是某个设备、某件事物或某个外部系统。在用例图中直线连接角色和用例,表示两者之间交换信息,称为通信联系。角色激活用例,并与用例交换信息。
2.用例
用例是一个可以被执行者感受到的、系统的、完整的功能。在UML中把用例定义成系统完成的一系列动作序列,动作的结果能够被特定的执行者察觉。这些动作除完成系统内部复杂计算与工作外,还包括与一些执行者的通信。用例通过关联与执行者连接,关联指出一个用例与哪些执行者交互,这种交互是双向的。
3.用例建模
用例建模是直接面向用户的,主要以需求陈述为依据,有关系统的业务边界、使用对象等,是构造系统用况模型的基本元素。用况建模的步骤如下:
(1)从几个方面识别系统的执行者,包括需要从系统中得到服务的人、设备和其他软件系统等。
(2)分析系统的业务边界或执行者对于系统的基本业务需求,并将其作为系统的基本用例。
(3)分析基本用例,将基本用例中具有一定独立性的功能,特别是具有公共行为特征的功能分解出来,将其作为包含用例供基本用例使用。
(4)分析基本用例功能以外的其他功能,将其作为扩展用例供基本用例进行功能扩展。
(5)分析并建立执行者与用例之间的通信关系。