购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

第1章
面向对象方法概论

本章首先简要地回顾传统软件开发方法中存在的问题,然后重点讨论面向对象的基本思想、主要概念和基本原则,论述面向对象方法的主要优点,并对面向对象方法的发展史和现状以及统一建模语言(Unified Modeling Language,UML)进行简介。

通过对本章的学习,读者要了解面向对象方法的主要内容,掌握基本知识,为进一步学习与应用面向对象分析和设计方法打下基础。

1.1 传统软件开发方法中存在的问题

20世纪60年代以前,软件开发者构造的软件系统的规模大多较小,且构造相对简单。那时所使用的编程语言和编程环境也相对简单,常见的编程语言有汇编语言以及随后出现的一些高级编程语言(如FORTRAN和COBOL等)。当时人们认为软件开发是一项强烈依赖个人技巧和技术能力的艺术性劳动,崇尚程序员的个人技能,没有认识到需要使用什么方法。那时产生的代码,按现在的人们所形容的,是意大利细面条式的,那是因为代码中含有较多的GOTO语句。

随着软件复杂性的增长,那种随心所欲的做法会带来问题,一个典型的问题是代码难以维护。一些高级编程语言试图解决所出现的问题,但这些语言并不能充分解决问题,因为软件开发也需要方法。

随后出现了多种软件开发方法,这些开发方法都能解决一些问题,但也都有一定的局限性。下面对三种典型的开发方法进行简要分析,以找出其中存在的主要问题。

1. 功能分解法

早期的一种开发方法称为功能分解法,它是以系统需要提供的功能为中心来开发系统的。它的基本思想为:首先定义顶层功能,然后把功能分解为子功能,同时定义功能之间的接口。对较大的子功能进一步分解,直到可给出明确的定义,进而根据功能/子功能设计数据结构和算法。

在那时,人们都认为功能分解法非常自然,因为它以系统需要提供的功能为中心来组织系统。此外,功能分解法也较好地运用了过程抽象原则。当时,计算机的应用还不是很普及,只有特定的用户有着软件需求,而且要求规模并不是很大。功能分解法的发明,在很大程度上解决了以前存在的问题,开发效率也有了很大的提高。特别是提出了模块化思想,并与模块化编程相结合,使得软件维护更加有效。这些是功能分解法在当时大受欢迎的主要原因。

使用这种以功能为中心的方法开发软件系统,一个显著特点是开始容易深入难。因为一开始按照功能需求进行自顶向下的功能分解是很直接的,但功能和功能接口这些系统成分却不能直接地映射到问题域中的事物,这导致所建立的功能模型难以准确而深入地描述问题域,而且也难以检验所建立的模型的正确性。特别是,该方法对需求变化性的适应能力差:需求的变化必定导致功能模块发生变化,一个功能模块的变化往往引起其接口发生变化,这又致使其他模块发生变化,最终的结果经常是局部的变化导致全局性的影响。

2. 结构化方法

结构化方法包括结构化需求分析、设计、编程和测试方法等。结构化需求分析使用数据流图、加工说明和数据字典来构造系统的需求分析模型。结构化需求分析方法比较严谨,使用它可避免很多错误和疏漏。此外,该方法也运用了逐步求精的原则,把加工逐步细化。结构化设计在需求分析的基础上,要针对给定的问题给出软件解决方案。结构化设计中的总体设计部分要给出被建系统的模块结构,详细设计部分要为各模块提供关于算法的详细描述。

结构化方法比功能分解法更强调对问题域的分析,但所使用的建模概念仍然不能直接地映射到问题域中的事物。需求的变化往往会引起相应的加工和数据流的变化,进而影响与之相关的其他加工和数据流的变化。系统复杂时也不能检验分析模型的正确性。此外,结构化需求分析与后续的结构化设计所采用的概念与表示法是不一致的(基于不同的概念体系),且转换规则不严格、具体,仅是指导性的,这致使从需求分析模型过渡到设计模型较为困难。

人们用功能分解法和结构化方法已经开发了很多软件系统,但是同时由于上述原因,对系统的开发与维护问题也日益显现出来。对于功能稳定的应用领域,如某些科学计算,上述方法是适用的。但对于众多的领域而言,它们的需求是易变的,如企业管理和商业管理领域就是如此。因为随着市场的变化,要对这些领域的管理模式不断地进行调整。对于较为复杂的系统,用上述方法进行软件开发,容易导致模块的低内聚和模块间的高耦合,从而使得系统缺乏良好的灵活性和可维护性。加上当时团队的开发与管理方法的不足,这些因素使得在20世纪70年代的软件危机情况更加严重。为了解决软件危机,人们对开发技术进行了一定的改进,对编程语言也进行了革新,如产生了用于软件开发的4GL、CASE工具、原型技术和代码生成器。这些努力取得了一定的成就,但没有从根本上解决问题。

3. 信息建模方法

信息建模方法是在实体联系模型(entity relationship model)的基础上发展起来的。该方法以称为实体的数据集合作为系统的构造块,即以数据结构为中心来开发软件。因为有相当多的人认为实体是稳定的,并且实体联系模型有相当好的理论基础,所以当时该方法为很多开发团队所采用。

对于数据及其关系比较复杂的系统来说,信息建模方法很有用。但它也存在弱点,即它仅对问题域中事物的数据方面进行了建模,而对功能行为在模型中没有体现。这也是信息建模方法常常与其他开发方法相结合使用的一个原因。

包括上述方法在内的几乎所有的传统方法都只注重于系统的一个或少数几个方面,对系统的其他方面建模的能力都很弱。典型地,功能分解法集中于将功能作为系统的构造块,对数据组织的功能较弱,即使是在结构化方法中,对数据组织的支持也不是很强;在信息建模方法中的构造块是实体,强调对数据的组织,但在该方法中忽略了系统功能。此外,上述方法都没有较强的描述系统的动态行为的能力。

软件学术界和产业界尝试了数十年,一直在寻找有效的开发复杂软件系统的方法。经过坚持不懈的努力,形成了面向对象方法。

面向对象方法是在传统方法的基础上发展起来的,例如仍使用抽象和模块化等概念。然而,面向对象方法与传统方法相比发生了根本性的变化,主要在于面向对象方法具有从多维度把所建立的模型与问题域进行直接映射的能力,在整个开发过程中均采用一致的概念和表示法,采用诸如封装、继承和消息等机制使得问题域的复杂性在模型上得以控制。

1.2 面向对象的基本思想

面向对象方法已深入到计算机软件领域的几乎所有分支。它不仅是一些具体的软件开发技术与策略,而且是一整套关于如何看待软件系统与现实世界的关系,用什么观点来研究问题并进行问题求解,以及如何进行软件系统构造的软件方法学。因而,面向对象方法有着自己的基本思想。

面向对象方法解决问题的思路是从现实世界中的客观对象(如人和事物)入手,尽量运用人类的自然思维方式从不同的抽象层次和方面来构造软件系统,这与传统开发方法构造系统的思想是不一样的。特别是,面向对象方法把一切都看成是对象。下面以开发一个开发票的软件为例来说明这种观点。发票的样本如图1-1所示。

图1-1 发票样本

按非面向对象思路,要定义数据结构(如C中的结构或Pascal中的记录)以及编写根据数据结构进行计算的函数或过程。而按面向对象思路,先把发票看成一个对象,其中有若干属性,如编号、名称和规格等,还有若干操作,如计算一种商品金额的操作“单项金额计算”和计算金额合计的操作“发票金额合计”,然后再根据具体编程语言考虑怎样实现这个对象。

人们已经形成共识:面向对象方法是一种运用对象、类、继承、聚合、关联、消息和封装等概念和原则来构造软件系统的开发方法。下面具体地阐述面向对象方法的基本思想:

1)客观世界中的事物都是对象(object),对象间存在一定的关系。面向对象方法要求从现实世界中客观存在的事物出发来建立软件系统,强调直接以问题域(现实世界)中的事物以及事物间的联系为中心来思考问题和认识问题,并根据这些事物的本质特征和系统责任,把它们抽象地表示为系统中的对象,作为系统的基本构成单位。这可以使系统直接映射到问题域,保持问题域中的事物及其相互关系的本来面貌。

2)用对象的属性(attribute)表示事物的数据特征;用对象的操作(operation)表示事物的行为特征。

3)对象把它的属性与操作结合在一起,成为一个独立的、不可分的实体,并对外屏蔽它的内部细节。

4)通过抽象对事物进行分类。把具有相同属性和相同操作的对象归为一类,类(class)是这些对象的抽象描述,每个对象是它的类的一个实例。

5)复杂的对象可以用简单的对象作为构成部分。

6)通过在不同程度上运用抽象原则,可以得到较一般的类和较特殊的类。特殊类继承一般类的属性与操作。

7)对象之间通过消息进行通信,以实现对象之间的动态联系。

8)通过关联表达类之间的静态关系。

图1-2为上述部分思想的一个示意图。

图1-2 面向对象基本思想(部分)的示意图

利用抽象原则从客观世界中发现对象以及对象间的关系,其中包括整体对象和部分对象,进而再把对象抽象成类,把对象间的关系抽象为类之间的关系。通过继续运用抽象原则,确定类之间存在的继承关系。上述简略地说明了建立系统的静态结构模型的思想,系统其他模型的建立原则也与此类似,这些内容将是本书讲述的重点。通过以图形的方式作为建模的主要方式之一,分别建立系统的分析与设计模型,进而得到可运行的程序。正是通过面向对象建模,对所要解决的问题有了深刻且完整的认识,进而把其转换成可运行的程序,使得程序所处理的对象是对现实世界中对象的抽象。

从上述可以看出,面向对象方法强调充分运用人类在日常逻辑思维中经常采用的思想方法与原则,如抽象、聚合、封装和关联等。这使得软件开发者能更有效地思考问题,并以其他人也能看得懂的方式把自己的认识表达出来。为了更全面和清楚地表达认识,面向对象方法要用多种图来详述模型,即从多方面来刻画模型。像一些开发方法一样,面向对象方法也要求从分析、设计和实现等不同抽象层次(开发阶段)来开发复杂的软件系统。

面向对象方法也是多种多样的,尽管各种面向对象方法不同,但都是以上述基本思想为基础的。还要指出的是,一种方法要包含一组概念和相应的表示法以及用其构造系统的过程指导,面向对象方法也不例外。贯穿于本书的面向对象概念及表示法均取自UML 2.4;至于过程指导,国内外尚无统一标准,本书给出的是基于特定活动而组织的,其特点是易学易用,且不失应用的普遍性。

1.3 面向对象的基本原则

面向对象的基本原则主要有抽象、分类、封装、消息通信、多态性、行为分析和复杂性控制。

(1)抽象

抽象(abstraction)是指从事物中舍弃个别的、非本质的特征,而抽取共同的、本质特征的思维方式。在面向对象方法中,可从几个方面来理解抽象:

1)编程语言的发展呈现抽象层次提高的趋势。例如,用C++编程,不用考虑CPU寄存器和堆栈中存放的内容,因为大多数编程语言都是从这些细节中抽象出来的。对于一个完成确定功能的语句序列,其使用者都可把它看作单一的实体(如函数),这种抽象就是过程抽象。在面向对象编程语言中,存在着过程抽象和数据抽象。在类的范围内,使用过程抽象来形成操作。数据抽象是指把数据类型和施加在其上的操作结合在一起,形成一种新的数据类型。类就是一种数据抽象,栈也是一种数据抽象。

2)在面向对象方法中,对象是对现实世界中事物的抽象,类是对对象的抽象,一般类是对特殊类的抽象。有的抽象是根据开发需要进行的。例如,就对象是对现实世界中的事物的抽象而言,高校中的学籍管理系统和伙食管理系统中所使用的学生的信息就是不一样的;再如,一个现实事物可能要担任很多角色,只有与问题域有关的角色,在系统中才予以考虑。

3)在面向对象的不同开发阶段需要进行不同程度的抽象。典型地,在面向对象分析阶段,先定义类的属性和操作,而与实现有关的因素在设计阶段再考虑。例如,对自动售货机建模,在分析阶段先定义一个类“自动售货机”,根据其收钱和发货的职责定义其属性和操作,其中对外提供的操作为收钱口、选择按钮和发货口(三者形成一个接口),而对于如何根据实现条件来设计它的内部细节是设计阶段的任务。这与现实生活中一样,我们可以在较高的抽象层次上分析与解决问题,然后再逐步地在较低抽象层次上予以落实。

从上述自动售货机的例子中能看到,使用抽象至少有如下好处:一是便于访问,外部对象只需知道有限的几个操作(作为接口)即可使用自动售货机对象;二是便于维护,如自动售货机的某部分有变化而其接口没有发生变化,只需在机器内部对该部分进行修改。甚至可用更优的具有相同接口的售货机对其进行替换,而不影响使用者的使用方式。

(2)分类

分类(classification)的作用是按照某种原则划分出事物的类别,以有助于认识复杂世界。

在OO中,分类就是把具有相同属性和相同操作的对象划分为一类,用类作为这些对象的抽象描述。如果一个对象是分类(类)的一个实例,它将符合该分类的模式。分类实际上是把抽象原则运用于对象描述时的一种表现形式。在OO中,进一步地还可以运用分类原则,通过不同程度的抽象,形成一般/特殊结构。

运用分类原则,清楚地表示了对象与类的关系,以及特殊类与一般类的关系。

(3)封装

封装(encapsulation)有两个含义:①把描述一个事物的性质和行为结合在一起,对外形成该事物的一个界限。面向对象方法中的封装就是用对象把属性和操纵这些属性的操作包装起来,形成一个独立的单元。封装原则使对象能够集中而完整地对应并描述具体的事物,体现了事物的相对独立性。②信息隐蔽,即外界不能直接存取对象的内部信息(属性)以及隐藏起来的内部操作,外界也不用知道对象对外操作的内部实现细节。在原则上,对象对外界仅定义其什么操作可被其他对象访问,而其他的对象不知道所要访问的对象的内部属性和隐藏起来的内部操作以及它是如何提供操作的。

通过封装,使得在对象的外部不能随意访问对象的内部数据和操作,而只允许通过由对象提供的外部可用的操作来访问其内部,这就降低了对象间的耦合度,还可以避免外部错误对它的“交叉感染”。另外,这样对象的内部修改对外部的影响变小,减少了修改引起的“波动效应”。图1-3所示的是封装的原理图,其中的一部分操作是外部可用的。

严格的封装也会带来问题,如编程麻烦,有损执行效率。有些语言不强调严格的封装和信息隐蔽,而实行可见性控制,以此来解决问题。例如,C++和Java就是这样的语言,通过定义对象的属性和操作的可见性,对外规定了其他对象对其属性和操作的可访问性;另外,一个对象也可以提供仅局限于特定对象的属性和操作,这可以通过把相应的可见性指定为受保护的或私有的来做到。

图1-3 封装的原理图

(4)消息通信

原则上,对象之间只能通过消息(message)进行通信,而不允许在对象之外直接地访问它内部的属性,这是由封装原则引起的。

消息必须直接发给特定的对象,消息中包含所请求服务的必要信息,且遵守所规定的通信规格说明。一条消息的规格说明至少包括:消息名、入口参数和可能的返回参数。一个对象可以是消息的发送者,也可以是消息的接收者,还可以作为消息中的参数。

(5)多态性

多态性(polymorphism)是指一般类和特殊类可以有相同格式的属性或操作,但这些属性或操作具有不同的含义,即具有不同的数据类型或表现出不同的行为。这样,针对同一个消息,不同的对象可对其进行响应,但所体现出来的行为是不同的。

(6)行为分析

关系机制提供了用关联、继承和聚合等组织类的方法。很多面向对象学者把系统模型的这部分结构称作静态模型,也有的称其为结构模型。通常,对系统还需要进行行为分析。

对于一个对象,由于其内的属性值在不断地发生着变化,按一定的规则根据属性值可把对象划分为不同的状态。在请求对象操作时,可能会使对象的状态发生改变,而对象的当前状态对随后的执行是有影响的。通过状态机图可以分析对象的状态变迁情况。

系统中的对象是相互协作的,通过发消息共同完成某项功能。这种协作的交互性可以用交互图来描述。

很多系统具有并发行为。从事物的并发行为的起因上看,事物的每个并发行为是主动发生的。体现在对象上,就是有一种对象是主动的,每个对象代表着一个进程或线程。在交互图上也能体现出对象间的并发行为。

(7)复杂性控制

为了控制系统模型的复杂性,引入了包(package)的概念。使用包可以把模型元素组织成不同粒度的系统单位,也可以根据需要用包来组织包。例如,用分析包和设计包来分别组织分析模型和设计模型,以显式地描述不同抽象层次的模型;对复杂类图也可以按类之间关系的紧密程度用包来组织类。

1.4 面向对象方法的主要优点

本节从认识论的角度和软件工程方法的角度看一下面向对象方法带来的益处,并把面向对象方法与传统方法进行比较,看面向对象方法有什么优点。

1. 从认识论的角度面向对象方法改变了开发软件的方式

面向对象方法从对象出发认识问题域,对象对应着问题域中的事物,其属性与操作分别刻画了事物的性质和行为,对象的类之间的继承、关联和依赖关系能够刻画问题域中事物之间实际存在的各种关系。因此,无论是系统的构成成分,还是通过这些成分之间的关系而体现的系统结构,都可直接地映射到问题域。这使得运用面向对象方法有利于正确理解问题域及系统责任。

2. 面向对象语言使得从客观世界到计算机的语言鸿沟变窄

图1-4为一个示意图,说明了面向对象语言如何使得从客观世界到计算机的语言鸿沟变窄。

机器语言是由二进制的“0”和“1”构成的,离机器最近,能够直接执行,却没有丝毫的形象意义,离人类的思维最远。汇编语言以易理解的符号表示指令、数据以及寄存器、地址等物理概念,稍稍适合人类的形象思维,但仍然相差很远,因为其抽象层次太低,仍需考虑大量的机器细节。非OO的高级语言隐蔽了机器细节,使用有形象意义的数据命名和表达式,这可以把程序与所描述的具体事物联系起来。特别是结构化编程语言更便于体现客观事物的结构和逻辑含义,与人类的自然语言更接近,但仍有不少差距。面向对象编程语言能比较直接地反映客观世界的本来面目,并使软件开发人员能够运用人类认识事物所采用的一般思维方法来进行软件开发,从而缩短了从客观世界到计算机实现的语言鸿沟。

3. 面向对象方法使分析与设计之间的鸿沟变窄

本书所讲的传统软件工程方法是指面向对象方法出现之前的各种软件工程方法,此处主要讨论结构化的软件工程方法。图1-5是结构化的软件工程方法的示意图。

图1-4 语言的发展使鸿沟变窄

图1-5 结构化的软件工程方法示意图

在结构化方法中,对问题域的认识与描述并不以问题域中的固有事物作为基本单位,并保持它们的原貌,而是打破了各项事物间的界限,在全局的范围内以功能、数据或数据流为中心来进行分析。所以运用该方法得到的分析结果不能直接地映射到问题域,而是经过了不同程度的转化和重新组合。这样就容易隐藏一些对问题域理解的偏差。此外,由于分析与设计的表示体系不一致,导致了设计文档与分析文档很难对应,在图1-5中表现为分析与设计的鸿沟。实际上并不存在可靠的从分析到设计的转换规则,这样的转换有一定的人为因素,从而往往因理解上的错误而埋下隐患。正是由于这些隐患,使得编程人员经常需要对分析文档和设计文档进行重新认识,以产生自己的理解再进行工作,而不维护文档,这样使得分析文档、设计文档和程序代码之间不能较好地衔接。由于程序与问题域和前面的各个阶段产生的文档不能较好地对应,对于维护阶段发现的问题的每一步回溯都存在着很多理解上的障碍。

图1-6是面向对象的软件工程方法的示意图。

图1-6 面向对象的软件工程方法示意图

面向对象开发过程的各个阶段都使用了一致的概念与表示法,而且这些概念与问题域的事物是一致的,这对整个软件生命周期的各种开发和管理活动都具有重要的意义。首先是分析与设计之间不存在鸿沟,从而可减少人员的理解错误并避免文档衔接得不好的问题。从设计到编程,模型与程序的主要成分是严格对应的,这不仅有利于设计与编程的衔接,而且还可以利用工具自动生成程序的框架和(部分)代码。对于测试而言,面向对象的测试工具不但可以依据类、继承和封装等概念与原则提高程序测试的效率与质量,而且可以测试程序与面向对象分析和设计模型不一致的错误。这种一致性也为软件维护提供了从问题域到模型再到程序的良好对应。

4. 面向对象方法有助于软件的维护与复用

需求是不断变化的(尽管可阶段性地“冻结”),这是因为业务需求、竞争形式、技术发展和社会的规章制度等因素都不断地在发生变化。这就要求系统对变化要有弹性。

在结构化方法中,所有的软件都按功能(可用过程或函数实现)来划分其主要构造块,最终的系统设计往往如图1-7所示。

图1-7 结构方法中的数据结构、算法及其间的关系

从图1-7中能够看出,数据结构与算法是分别组织的,对一处修改,可能会引起连锁反应。这种建模的缺点是模型脆弱,难以适应不可避免的错误修改以及需求变动,以至于系统维护困难。算法和数据的分离,是造成这种状况的根本原因。算法和数据间的可能的紧密耦合,也使得复用难以实现。

在面向对象方法中,把数据和对数据的处理作为一个整体,即对象。该方法以对象及交互模式为中心,如图1-8所示。

图1-8 面向对象方法中的数据结构、算法及其间的关系

通过与结构化方法的比较,能够看出,面向对象方法还具有如下的主要优点:

1)把易变的数据结构和部分算法封装在对象内并加以隐藏,仅供对象自己使用,这保证了对它们的修改并不会影响其他的对象。这样对需求的变化有较强的适应性,有利于维护。对象的接口(供其他对象访问的那些操作)的变化会影响其他的对象,若在设计模型时遵循了一定的原则,这种影响可局限在一定的范围之内。此外,由于将操作与实现的细节进行了分离,这样若接口中的操作仅在实现上发生了变化,也不会影响其他对象。对象本身来自客观事物,是较少发生变化的。

2)封装性和继承性有利于复用对象。把对象的属性和操作捆绑在一起,提高了对象(作为模块)的内聚性,减少了与其他对象的耦合,这为复用对象提供了可能性和方便性。在继承结构中,特殊类对一般类的继承,本身就是对一般类的属性和操作的复用。

5. 面向对象方法有助于提高软件的质量和生产率

按照现今的质量观点,不仅仅要在编程后通过测试排除错误,而是要着眼于软件开发过程的每个环节开展质量保证活动,包括分析和设计阶段。系统的高质量不是仅指系统没有错误,而是系统要达到好用、易用、可移植和易维护等,让用户由衷地感到满意。采用OO方法进行软件开发,相对而言更容易做到这些。

有很多数据表明,使用OO技术从分析到编程阶段能大幅度地提高开发效率,在维护阶段提高得就更多。这主要体现在如下几方面:

·OO方法使系统更易于建模与理解。

·需求变化引起的全局性修改较少。

·分析文档、设计文档、源代码对应良好。

·有利于复用。

1.5 面向对象方法的发展史及现状简介

在这里把面向对象方法的发展分为三个阶段:雏形阶段、完善阶段和繁荣阶段。

(1)雏形阶段

20世纪60年代挪威计算中心开发的Simula 67,首先引入了类的概念和继承机制,它是面向对象语言的先驱。该语言的诞生是面向对象发展史上的第一个里程碑。随后20世纪70年代的CLU、并发Pascal、Ada和Modula-2等语言对抽象数据类型理论的发展起到了重要作用,它们支持数据与操作的封装。犹他大学的博士生Alan Kay设计出了一个实验性的语言Flex,该语言从Simula 67中借鉴了许多概念,如类、对象和继承等。1972年Palo Alno研究中心(PARC)发布了Smalltalk-72,其中正式使用了“面向对象”这个术语。Smalltalk的问世标志着面向对象程序设计方法的正式形成,但是这个时期的Smalltalk语言还不够完善。

(2)完善阶段

PARC先后发布了Smalltalk-72、76和78等版本,直至1981年推出该语言完善的版本Smalltalk-80。Smalltalk-80的问世被认为是面向对象语言发展史上最重要的里程碑。迄今绝大部分面向对象的基本概念及其支持机制在Smalltalk-80中都已具备。它是第一个完善的、能够实际应用的面向对象语言。但是随后的Smalltalk的应用尚不够广泛,其原因是:

1)追求纯OO的宗旨使得许多软件开发人员感到不便。

2)一种新的软件开发方法被广泛地接受需要一定的时间。

3)针对该语言的商品化软件开发工作到1987年才开始进行。

(3)繁荣阶段

从20世纪80年代中期到90年代,是面向对象语言走向繁荣的阶段。其主要表现是大批比较实用的面向对象编程语言的涌现,例如C++、Objective-C、Object Pascal、CLOS(Common Lisp Object System)、Eiffel和Actor等。这些面向对象的编程语言分为纯OO型语言和混合型OO语言。混合型语言是在传统的过程式语言基础上增加了OO语言成分形成的,在实用性方面具有更大的优势。此时的纯OO型语言也比较重视实用性。现在,在面向对象编程方面,普遍采用语言、类库和可视化编程环境相结合的方式,如Visual C++、JBuilder和Delphi等。面向对象方法也从编程发展到设计、分析,进而发展到整个软件生命周期。

到20世纪90年代,面向对象的分析与设计方法已多达数十种,这些方法都各有所长。目前,统一建模语言(Unified Modeling Language,UML) [ 9 ] 已经成为世界性的建模语言,适用于多种开发方法。把UML作为面向对象的建模语言,不但在软件产业界获得了普遍支持,在学术界影响也很大。在面向对象的过程指导方面,目前还没有国际规范发布。当前较为流行的用于面向对象软件开发的过程指导有“统一软件开发过程” [ 6 ] (也有人称为RUP)和国内的青鸟面向对象软件开发过程指导等。

当前,面向对象方法几乎覆盖了计算机软件领域的所有分支。例如,已经出现了面向对象的编程语言、面向对象的分析、面向对象的设计、面向对象的测试、面向对象的维护、面向对象的图形用户界面、面向对象的数据库、面向对象的数据结构、面向对象的智能程序设计、面向对象的软件开发环境和面向对象的体系结构等。此外,许多新领域都以面向对象理论为基础或作为主要技术,如面向对象的软件体系结构、领域工程、智能代理(Agent)、基于构件的软件工程和面向服务的软件开发等。

1.6 关于统一建模语言UML

UML最初是在多种面向对象分析与设计方法相互融合的基础上形成的,后来发展成为也可以用于业务建模以及其他非软件系统建模的语言。它于1997年11月被对象管理组织(Object Management Group)采纳为建模语言规范,随后被产业界和学术界广泛接受。

UML定义了建立系统模型所需要的概念并给出了表示法,但它并不涉及如何进行系统建模。因此它只是一种建模语言,而不是一种建模方法。UML是独立于开发过程的,也就是说它可以适用于不同的开发过程。

UML 2.4规范由四个部分组成:基础结构(infrastructure)、上层结构(superstructure)、对象约束语言(object constraint language)和图交换(diagram interchange)。简言之,基础结构给出了用于定义建模语言的核心构造物,上层结构定义了建模语言——UML,对象约束语言用于以精确的方式描述基础结构、上层结构以及用户建立的模型中的查询表达式和约束,图交换规定了如何定义用于数据交换的XML文件的格式。

可见UML 2.4不仅仅适用于软件系统建模,其中还包含了大量的用于定义自身的元素。关心如何构造建模语言以及开发建模工具的读者要掌握上述的四个部分;关心对应用系统建模的读者应该掌握上层结构部分,至少要掌握主要建模元素的定义,如果需要在模型中精确地定义查询表达式和约束,还要掌握对象约束语言。

尽管UML已经得到了广泛应用,但它还存在不少缺点。对于以前的UML 1.x,来自学术界的主要批评是其语法和语义不够严格;来自产业界的主要批评是它的内容过于庞大,概念过于复杂。至今UML已经开始了版本2.x的发展,目前的UML 2.4就比以前的版本有了显著的改进和提高,然而仍有不少问题没有得到令人满意的解决。特别是,它的复杂性不但没有如人们的期望那样得到控制,反而比以往更为庞大和复杂。对于UML存在的问题以及解决方法的深入讨论,请参阅文献[17]和[18]。

针对庞大且复杂的UML,本书的原则是采用其中的在面向对象建模中常用的概念和表示法,并梳理出清楚的语义。

下面就UML 2.4对面向对象建模的支持而言,对UML 2.4支持的14种模型图予以简介,见图1-9。

图1-9 UML 2.4中的图的种类以及其间的关系

UML 2.4支持的模型图在逻辑上分为两大类:结构图(structure diagram)和行为图(behavior diagram)。

结构图用于对系统的静态方面建模。结构图分为:

·类图(class diagram)。它是描述系统中各个对象的类型以及其间存在的各种关系的图。

·组合结构图(composite structure diagram)。它是描述类和构件的内部结构的图,其中包括与系统其他部分的交互点。

·构件图(component diagram)。它是描述构件的组织结构和相互关系的图,用于表达如何在实现时把系统元素组织成构件,从而支持以构件为单位进行软件制品的实现和发布。

·部署图(deployment diagram)。它是描述节点、节点间的关系以及构件和节点间的部署关系的图。

·对象图(object diagram)。它是描述在某一时刻一组对象以及它们之间的关系的图。

·包图(package diagram)。它是描绘模型元素分组(包)以及分组之间依赖的图。

·剖面图(profile diagram)。它是在UML 2.4的基础上定义新建模元素的图,用以增加新的建模能力。

行为图用于对系统的动态方面建模。行为图分为:

·活动图(activity diagram)。它是描述活动、活动的执行顺序以及活动的输入与输出的图。

·用况图(use case diagram)。它是描述一组用况和参与者以及它们之间的关系的图。

·状态机图(state machine diagram)。它是描述一个对象或其他实体在其生命周期内所经历的各种状态以及状态变迁的图。

·交互图(interaction diagram)。它是顺序图、交互概览图、通信图和定时图的统称。

·顺序图(sequence diagram)。它是描述一组角色和由扮演这些角色的实例发送和接收的消息的图。

·交互概览图(interaction overview diagram)。它是以一种活动图的变种来描述交互的图,它关注于对控制流的概览,其中控制流的每个节点都可以是一个交互图。

·通信图(communication diagram)。它是描述一组角色、这些角色间的连接件以及由扮演这些角色的实例所收发的消息的图。

·定时图(timing diagram)。它是描述在线性时间上对象的状态或条件变化的图。

习题

1. 与传统软件开发方法相比,面向对象方法有什么优点?

2. 查阅资料,进一步讨论UML与面向对象方法的关系。

3. 封装的目的是什么?在面向对象方法中封装的目的是如何达到的?

4. 针对你过去使用传统开发方法所构造的系统的不足,总结一下问题的原因。考虑如果使用面向对象方法,在哪些方面可能会获益。

5. 面向对象方法的一个主要原则是抽象。思考一下在工作和学习中你经常在什么场合下运用抽象原则。 2OUcP3H5Rzc8sFqT99fBMwjFSByJkOXHwTP/vJ093RYHZUwad2vsZ+pcSAv+piL5

点击中间区域
呼出菜单
上一章
目录
下一章
×