面向对象方法_面向对象方法论文

面向对象方法_面向对象方法论文

面向对象方法论,本文主要内容关键词为:方法论论文,面向对象论文,此文献不代表本站观点,内容供学术参考,文章仅供参考阅读下载。

20世纪80年代,一种全新的计算机软件设计方法开始风靡全球,这就是面向对象技术。它已经在计算机科学、信息科学和系统科学中得到了有效的应用,显示出其强大的生命力。

用计算机解决问题时需要用程序设计语言对问题的求解加以描述,软件是问题求解的一种表述形式。显然,如果软件能够直接地表达求解问题的方法,则软件不仅易于被人理解,而且易于维护和修改,从而提高了软件的可靠性和可维护性。此外,如果能够按照人们通常的思维方式来建立问题域模型,就可以提高公共问题域中软件模块化和重用化的可能性。而面向对象方法正是按人们通常的思维方式来建立问题域的模型,并设计出尽可能自然地求解问题的软件。

面向对象是以对象为中心的方法。面向对象方法有如下基本特征[(1)]:(1)对象是数据和有关操作的封装体。它突破了传统的将数据与操作分离的模式,较好地实现了数据的抽象;(2)面向对象方法的继承性体现了概念分离抽象。在对象继承结构上,下层对象继承上层对象的特征(属性和操作),因而面向对象方法便于软件的演化和增量式的扩充;(3)面向对象方法用消息将对象动态链接在一起。与传统的模块调用不同,面向对象方法采用了灵活的消息传递方式,从而便于在概念上体现并行和分布式结构;(4)面向对象方法具有信息隐藏性。对象将其实现细节隐藏在它的内部,因此无论是对象概念的完善扩充,还是对象实现的修改,影响仅限于该对象内部,而不会对外界产生影响。这就保证了面向对象软件的可构造性和易维护性。

面向对象技术最初是从面向对象的程序设计语言开始的,它的出现是以本世纪60年代末Simula语言为标志的。到了80年代随着Smalltalk语言和环境的出现,掀起了面向对象研究的高潮。后来,Ada的推广和应用有力地推动了面向对象技术的发展。到80年代中期,面向对象语言已呈百花齐放的局面,各种不同风格的面向对象程序设计语言不断出现,达数十种之多。其中较为著名的有:Smalltalk,C++,Objective,CLOS,eiffel等。

随着研究的不断深入,面向对象技术的应用越来越广泛,面向对象的思想被应用于许多不同的领域,如程序设计语言、软件开发方法学、操作系统、人工智能、时实系统、数据库、人机界面,甚至硬件设计,面向对象的技术逐渐成熟起来。

传统软件设计方法存在的问题

从60年代末开始,计算机软件的作用已经得到普遍的重视,各种大型的、复杂的软件系统陆续问世。但是,随着软件系统规模的扩大和复杂性的增加,软件的开销(开发软件时所耗费的人力、物力和运行时所占用的硬件资源及运算时间)也惊人地增加了,软件系统的可靠性和可维护性却明显地降低了。人们惊呼这是一种危机!产生这种危机的根本原因是:用冯·诺依曼机进行问题求解的问题空间结构与冯·诺依曼机所用的求解问题方法的方法空间结构的不一致性。这种不一致性主要表现在以下几个方面[(2)]:

(1)人们在认识问题、分析问题时,是把问题分解为一些对象以及各对象间的组合和联系。但冯·诺依曼机所能直接接受的是面向过程的语言,在这种机器上运行的传统软件是遵循数据/过程这样的风格编写的。它是由一组被动的数据和一组能动的过程所组成的。其中,数据表示某种信息,而过程表示对数据的处理,激活后的过程即为进程。这种面向过程的语言是一种比较难理解的、与人的自然语言距离较远的语言。当然,最理想的计算机语言应该是最接近人类自然语言的语言。而目前在计算机语言和人的自然语言之间还存在着一条鸿沟。

(2)程序设计过程也就是一个软件的开发过程。最典型的传统方法是遵循结构化需求分析、结构化系统设计和结构化程序设计这样的过程和方法。这种方法在本质上具有冯·诺依曼机系统的结构特点,是软件开发人员从开发软件的立场出发而确定的,并不是从人们认识客观世界的过程和方法出发的。

(3)传统的计算机虽然也有各种各样的体系结构,但都未能从根本上改变冯·诺依曼机的基本特征,即:顺序地执行指令,按地址访问线性存储空间,数据和指令在机器内部采用统一的表示形式,以及数字计算等。对用户来说,这种机器(裸机)的功能是很有限和很不直观的。为了满足用户的需求,就在裸机上利用软件来构造不同层次的虚拟机,每一层虚拟机都可以看作是一种语言的翻译或解释,用这种方法来填补用户和裸机之间的鸿沟。但虚拟机的层次越多,软件的开销就越大,可靠性和可维护性就越低。

从上面的分析中可以看出,语言鸿沟是形成软件危机的主要原因之一。弥补这一鸿沟的最根本办法是使未来的计算机能接受、理解和处理人的自然语言。但从目前的理论和技术来看,还存在着一系列困难。

当一个有数十年实践经验的工程师回首往事时,经常把自己以往所完成的一些工程称为“遗憾工程”。这是因为当系统设计开始时(概念设计阶段),用户对系统的需求是比较笼统和抽象的,而那时设计者的设计“自由度”较大,设计者可选用当时已有的原理、方法、工具、环境、构件和器件去设计系统。随着时间的推进,用户对系统的需求越来越细致和具体,但设计者对系统进行修改的“自由度”却越来越小了。还应该看到,随着时间的推移,原理、方法、工具、环境、构件和器件的水平是日益提高的,而设计者采用新技术的“自由度”却受到了限制。因此,系统越大、周期越长、成为“遗憾工程”的可能性就越大。

为了解决上述这种不合理的现象,就应使我们分析、设计和实现一个系统的方法尽可能地接近我们认识一个系统的方法。换言之,就是应使描述问题的问题空间和解决问题的方法空间在结构上尽可能地一致,也就是使我们分析、设计和实现系统的方法学原理与我们认识客观世界的过程尽可能地一致。这就是面向对象方法论的出发点和所追求的基本原则。

面向对象的软件设计方法

(1)面向对象的基本原则和方法

面向对象的系统分析和设计方法的目的和任务主要是为了提高生产率,保证软件质量,加强软件的可维护性。为了达到这个目的,面向对象软件分析和设计方法必须遵循如下的原则[(3)]:

①构造和分解相结合的原则。构造是指基本对象组装成复杂对象或活动对象的过程;分解是指对大粒度对象进行精细化从而完成对系统模型的细化过程,这两者的结合是软件工程中系统分析和设计的基础。

②抽象化和具体化相结合的原则?在系统开发中,抽象指的是在决定如何实现实在对象之前,对象的意义和行为。使用抽象可以尽可能早的避免考虑一些细节。抽象有两种机制:一是数据抽象,它是分析和设计的核心,是组织和建立系统规格说明和设计说明的基础。数据抽象把一组数据对象及作用在其上的操作组成一个程序实体,使得外部只知道它做什么,而不必知道它如何做,也不必知道其数据对象是如何表示的。二是过程抽象,它为对象的相互作用提供了依据。具体化是指在精细化过程中,对对象的必要细节加以刻划,它有助于确定系统对象,加强系统模型的稳定性。

③封装的原则。封装指的是将对象的各种独立的外部特性与内部实现细节分开。封装防止了由于程序的相互依赖性而带来的变动影响。基本思想是使系统的每个部分都封装或者隐藏一个设计决策;每个模块的接口设计尽可能少地与其内部工作状态相联系。在开发新的系统时,封装有助于最大限度地减少重复劳动。

④继承的原则。继承指的是能直接获得已有的性质和特征而不必重复定义它们。分析和设计不同定义对象的公共部分,只需要一次性地指定公共属性和操作,然后特殊化并发展这些属性及操作成为特殊情况。当然,继承者也可以在继承的基础上定义自己独有的特性。调用操作不需要考虑操作对应多少实现方法。操作的多态性解决了这个问题。

⑤相关的原则。它包括静态结构的关系,即整体和部分,全体和成员等,也包括动态特性和关系,如通信关系等。

⑥行为分类的原则,行为分类就是要区分基于直接原因的行为,时变性行为和功能相似性行为。

目前软件工程领域的一个研究重点是面向对象的软件设计方法学。由于面向对象的方法是根据稳定的对象建立系统模型,因而中心模型往往是稳定的,可以很好地适用需求的变化,具有良好的可维护性、可扩充性和可重用性。从80年代后期开始,已有人陆续提出了一些面向对象的方法学。具有代表性的工作有:

①Peter Coad和Ed Yourdon的OOA/OOD[(4)]。这是Peter Coad和EdYourdon在1990年提出的一种循序渐进的面向对象的系统分析和设计方法。强制系统分析包括五个步骤:确定对象;标识结构;定义主题;定义属性;定义服务。设计包括四个步骤:设计问题域;设计人机交互部分;设计任务管理部分;设计数据管理部分。这样,分析把系统横向划分为五个层次,数据把系统纵向划分为四个部分。形成一个清晰的系统模型。该方法包含一种图示的框架结构,有类、实例、继承、对象间的通信等基本成分。确定对象的方法是启发式的。但对对象的动态特性缺乏系统的考虑。

②Booch的OOD[(5)]。这是Booch于1990年提出来的,它继承了Abbot(1983)的思想,主要包括下面四个步骤:在一个给定的抽象级别上标识出类和对象;标识出这些类和对象的语义;标识出这些类和对象之间的关系;重复以上三个步骤,直到分析和设计结束。分析和设计的结果模型可以从逻辑观点和物理观点两个方面来看。逻辑观点主要是指系统的模块和进程结构。物理观点主要是指状态转换图和时间图。该方法提供了丰富的图形技术和文档技术,可用来灵活地进行分析和设计。这是一种由外而内的方法,从外面开始逐步标识类和实例。它最为缺乏的是为每个类和对象确定操作的技术。

③ESA和HOOD[(6)]。这个方法是为欧洲航天局(ESA)开发的,后经过HOOD小组的进一步工作于1989年推出。HOOD软件用Ada编写。HOOD的分析和设计包括三个步骤:定义问题;详细描述非形式化的解决策略;策略的形式化;解决的形式化。其中策略的形式化又分为五个步骤:标识对象;标识操作;组装对象的操作;图形描述;调整设计决策。每个层次上的各个对象归档在HOOD的章节中。每个HOOD章节是上述步骤的子部分。系统有层次结构,所以文档也有层次结构。HOOD是完全面向Ada的。这样做的好处是使系统开发者不需要学习更多的语法和语义。该方法给出了基本设计步骤,但是没有给出找到合适对象的方法。事实上,HOOD不能有力的支持包含结构,特别是继承结构。

④Rumbaugh等的OMT[(7)]。是Rumbaugh等在1989年提出的。它是在实体-关系模型的基础上扩展了类、继承和行为得到的。这种技术又被Blala和Premerlani以及Rumbaugh扩展应用于数据库的设计。该方法主要分三个步骤:给出类及它们之间的关系描述的系统静态结构-对象模型;用对象的事件、状态和响应来刻划对象的时序性质,得到动态模型;按对象的操作刻划出如何由输入得到输出的功能模型。分析和设计的结果是对象关系图、数据流图和事件、状态和响应图。该方法是发展最完善的一种方法,它包括几种不同的观点来刻划不同的模型。

⑤Wirfs-Brock的Rdd[(8)]。这是Wirfs-Brock等于1990年提出的一种用类、责任及它们的合作来建立系统模型的方法。该方法分为探测阶段和细化阶段。探测阶段分三个步骤:确定类;为每个类确定其责任,通过分析类的动作和类间关系来完成;确定类间的合作,这些合作使得类能够实现它的责任。细化阶段也分为三个步骤:找出类间的层次关系;通过一组类的合作构成子系统;给出各个操作的模型。分析的结果得到类层次图、子系统和合作关系图、类规范、子系统规范、由类和子系统支持的合同规范。Rdd是一种非形式化的分析和设计方法,它找出类及其性质的策略完全依赖于设计者的技术。

除上述方法外,还有Shlear和Mellor的OOSA,Wasserman的OOSD,Reenksang的OORASS,Embley的OSA,Gibon的OBA,Page-Jongs和Weiss的SYNTHESIS等多种方法[(9)]。

(2)面向对象程序设计方法的基本概念

我们用一个简单的公式来表达对面向对象程序设计含义的理解:

面向对象程序设计=对象+类+继承

对象(Object):是由属性和作用于属性之上的方法(又称操作、服务)集组成。对象把属性和服务封装在一起,是一个动态的观念。其中的属性集反映了对象当前的状态。方法有两类:一类是通过返回对象当前的某个属性值来向外界反映对象当前的状态;另一类是通过改变对象的某些属性值来改变对象当前的状态。

类(Class):用来描述具有相同的属性和方法的对象的集合。它定义了该集合中的每个对象所共有的属性和方法。对象是类的实例。类是由类型和模块的概念相结合而产生的。从理论上说,它是ADT(抽象数据类型)的实现。因此,类具有ADT的优点:不是通过实现,而是通过数据结构和数据结构上的一组服务(即方法)以及这些服务的形式化特征来描述数据结构类的。这样,类就可以将该类对象的属性和方法的描述及实现分离开。为类的封装提供了方便。

继承(Inheritance):它在类与类之间建立了这样一种关系:一个类可以定义为另一个类的扩充或受限。这样,就可以通过继承关系用原有的类来构造新的类。原有的类被称作父类,新类被称作子类。父类中的成员(属性和方法)被子类所继承。通过继承,程序员可以从现实中抽取具有普遍意义的类。然后,通过继承来复用这些类,减少代码的编写数量。另外,继承中子类可以对父类中的成员进行修改,这符合程序员在实际编程中逐步求精的思考方法。尤其是对于那些软件设计初期需求不可能完全描述清楚以及需求经常有所变化的场合。

多态(Polymorphism):是指一个多态引用可以指向多个类型实例。因此,对于一个多态引用要用两个方面来描述它的类型:静态类型和动态类型。静态类型是指多态引用被声明的类;动态类型是指它所指向的实例的类型。

动态链接(Dynamic Binding):链接是指将被调用过程的代码与调用点相链接。对于动态链接来说,建立是在抽象的执行过程中动态完成的。通常动态链接是和继承、多态链接联系在一起的。

(3)程序设计语言对面向对象方法的支持

在分析程序设计语言对面向对象方法支持的程度时,通常将它们分成三类:①抽象数据类型方式:找出数据抽象,分离描述和实现,限制过程对数据的访问。②模块方式:支持数据抽象和封装,但不提供继承机制。③真正的面向对象语言:支持数据抽象、封装、继承、多态和动态链接。

对于非面向对象语言,我们用语言上的某些特殊技术来部分地实现OOP(面向对象编程)在实现过程中,一项重要任务是手工地将面向对象的概念映射到目标语言上,而不是象面向对象抽象设计语言那样由编译程序自动完成。其中的主要构造有:将类翻译成数据结构,为对象分配内存,实现数据结构的继承以及封装数据结构内部细节。

C语言由于自身的灵活性,能够很容易地实现类、实例、单重继承等。但是,要想在C语言中进一步挖掘出面向对象的概念却很难。

FORTRAN77语言提供了有限的支持。FORTRAN77提供的例程的多入口点(multiple entry points),可被用来构造那些管理抽象对象的模块。但是,它不允许内部调用等限制阻碍了其进一步向面向对象的发展。Ada语言的封装机制和类属(generic)机制作得比较好,但是它不提供任何继承机制,虽然可以用类属方法模拟继承,但是代价太高,不现实。

C++语言是近年来应用比较广泛的面向对象编程语言,它是在C语言的基础上引入了支持面向对象方法的机制而实现的一种程序设计语言。除了少量差别外,几乎可以将C++语言看作C语言的超集。作为一种更好的C,C++语言也加强了对C语言特性的支持。如:函数重载;内联函数(inlinefunction);引用类型(reference type);const常量说明;针对函数重载和模块之间函数调用所进行的安全性和一致性检查。

除了上述的特性外,C++的面向对象特性主要有如下几点:

类。C++中类是用关键字class来声明的。在C++中称类的属性为数据成员,类的方法为成员函数。操作符函数与普通的函数一样,可以作为成员函数,可以重载。对象是类的实例。在C++中,通过成员的可视性(visibility)来实现封装。一般来说,类成员的可视性有三种:私有的(private)、公有的(public)和保护(protected)。私有的数据成员和成员函数是不透明的,不能在类的作用域之外访问,而公有的数据成员和成员函数是透明的,可以在类的作用域之外访问。保护的数据成员和成员函数则只能够在该类的作用域及其子类的作用域之内访问。类中的函数成员对该类的数据成员具有无限制的存取权,面对该类作用域之外的数据和函数成员的存取受到限制。构造函数是用来自动地初始化类对象的成员函数,它的名字与类名相同。对于含有对象成员的类来说,该类的构造函数还要通过声明对象成员初始化表来创建对象成员。析构函数名是在类的名字前加波浪号~,它没有变元也没有返回类型。析构函数完成与构造函数相反的功能,负责释放构造函数中分配的内存等。C++提供了多态创建和删除对象的运算符:New和Delete。

派生类和继承。派生类是C++提供继承的基础。C++允许派生类集成或修改父类的部分或全部方法,而且可以提供父类中没有的新方法。C++支持多重集成。另外,在C++中如果不是特别授权的话,派生类不能访问其父类的私有数据。授权的方式有两种:第一种是整个派生类或派生类中的某些方法可以声明为父类的友元。第二种方式是利用类定义中的保护部分,私有被声明为protected的类成员,除了对派生类以外,也象私有成员那样被隐藏起来。在以继承为基础的层次化类结构中,C++为类成员的存取提供了极为丰富的手段。

多态和虚拟函数。C++中采用了虚拟函数的方法来实现多态性。虚拟函数用关键字virtual声明。当父类定义了一个虚拟函数而且派生类也定义了一个同样的虚拟函数时,编译程序能够确定对象应该调用哪个函数。在实现过程中,编译程序给虚拟函数建立一个该类的隐藏数据成员,这个隐藏数据成员是对象实际所属类的虚拟函数的指针。当调用这个虚拟函数时,编译程序就通过这个隐藏指针来调用虚拟函数。虚拟函数在父类和派生类中的定义形式要完全一样,具有相同的名字、返回类型和参数表。

C++的I/O流。C++的I/O系统由与流有关的类层次结构来定义。这些定义都可在头文件iostream.h中找到。最底层的类称为streambuf,它提供没有格式支持的最基本的操作;上一层称为ios类,ios类提供了格式化I/O的基本支持,可以用它去创建流。它有三个派生类:istream(输入流)ostream(输出流)和iostream(输入和输出流)。C++提供了重载运算符<<和>>来完成实际的I/O操作。

面向对象方法与自然科学认识的辩证法

我们在认识和研究客观世界时应从“对象”入手,然后再转向“过程”。经验告诉我们,在客观世界以及作为它的映射的软件系统中,“过程”和“操作”是不稳定的、多变的,而“对象”和“数据结构”则是相对稳定的。因此,以“过程”入手(或以“过程”为中心)来设计软件,则思维成果的可重用性必然较差,而以“对象”或以“数据结构”入手(或以“对象”或“数据结构”为中心),则软件的主体结构比较稳定,所得的思维成果的可重用性就可能较好。当然,在这种设计过程中还必须同时考虑到进一步转向研究“过程”的可能和方便。

面向对象的程序设计方法正是遵照这样的原则进行的。它虽然是以数据结构为中心,但又充分考虑到体现“过程”和“操作”的方便,例如,在每种类的数据结构周围安排了各种有关的操作,这些操作即可以定义数据结构的语义,又可以表达对这些数据结构的操作。总之,以往的程序设计方法的主要缺点是不能直接地反映人们求解问题的方法和方式,因而产生了问题空间和方法空间在结构上的不一致。而面向对象的程序设计方法则是尽可能地争取这两者在结构上的一致性。

面向对象方法和技术从信息模拟的角度来说,它意味着表示现实世界中的某些事物,以及该事物的某些实例。从面向对象的程序设计语言角度来说,它意味着表示某些处理和数值的运行实例,这些实例是由一个叫做“类”的静态描述所定义的。面向对象方法可以表示为:

面向对象方法=对象+类+继承+消息通信和人们认识世界的规律一样,面向对象的基本方法学认为:客观世界是由许多各种各样的对象所组成的,每种对象都有各自的内部状态和运动规律,不同对象间的相互作用和联系就构成了各种不同的系统,构成了我们所面对的客观世界。当我们设计和实现一个客观系统时,如果能在满足需求的条件下把系统设计成是由一些不可变的(相对固定的)部分所组成的最小集合,则这个设计就是优秀的,而这些不可变的(相对固定的)部分就被看成是一些不同的对象。

面向对象技术是属于思维科学中的一项工程技术,面向对象的方法学是属于思维科学中的一项技术科学,思维科学包括抽象思维、形象思维和灵感(顿悟)思维三个组成部分[(10)],但目前的认知科学还很少涉及灵感思维的问题。

抽象思维是以抽象的概念为基础的,形象思维是以具体的形象为基础的。从人们认识世界和获取知识的认识过程来看,不论是抽象思维还是形象思维,主要是通过从一般到特殊的演绎方法和从特殊到一般的归纳方法来进行的。数百年来,人们对抽象思维的研究已取得一系列的成果,对形式逻辑、辩证逻辑和数理逻辑都已建立了有关演绎和归纳的较完整的理论和方法体系。在形象思维中,这种演绎或归纳都是在形象间的“相似”这一关系上进行的。当人们利用形象思维去认识客观事物和改造客观事物时,首先是“按照相似原理和关系,把所要研究的问题区分成一定的相似系统与类别”,“分类之后,进一步对事物进行详细的解剖和分析”,解剖分析后再进行“综合优化”,并在事物的运动中和运动的相互关系中去考察客观事物的静态相似和动态相似关系、宏观相似和微观相似关系、纵向相似和横向相似关系[(11)]。

面向对象技术就是遵循上述认识方法学的基本概念而建立自己的方法学基础的。面向对象方法学认为:客观世界是由各种“对象”所组成的,任何事物都是对象,每一个对象都有自己的运动规律和内部状态,每一个对象都属于某个对象“类”,都是该对象类的一个元素。复杂的对象可以是相对比较简单的各种对象以某种方式而构造的。不同对象的组合及相互作用就构成了我们要研究、分析和构造的客观系统。

面向对象方法学还认为:通过类比,发现对象间的相似性,即对象间的共同性,这就是构成对象类的根据。在按“类”、“子类”、“父类”(或“超类”)的概念构成对象类的层次关系(或树形结构)时,如不加特殊说明,则处在下一层次的对象可以自然地继承位于上一层次上的对象的属性。对于已分成类的各个对象,可以通过定义一组“方法”来说明该对象的功能,也即是:允许作用于该对象上的各种操作。对象间的联系是通过传递“消息”来完成的,消息就是通知对象去完成一个允许作用于该对象的操作。至于该对象将如何完成这个操作的细节,则是封装在相应的对象类的定义中,对于外界是隐蔽的。

综上所述,面向对象的方法学是比较自然地模拟了人类认识客观世界的方式。从方法学的角度来看,如果有可能利用现有信息技术的手段来实现形象思维的载体和表示方法,则面向对象的方法学就不只是适用于对抽象(逻辑)思维的表示和处理,也有可能适用于对形象(直觉)思维的表示和处理。

面向对象的方法和技术并没有完全从根本上解决目前所存在的计算机软件危机,但是面向对象的方法远远优于传统的软件设计方法,并且得到了相当广泛的应用。同时,面向对象的方法为我们在认识论和方法论上提供了认识客观世界的有效方法,因此,这种方法具有广阔的应用价值。

标签:;  ;  ;  ;  ;  ;  ;  ;  ;  ;  ;  ;  ;  

面向对象方法_面向对象方法论文
下载Doc文档

猜你喜欢