第二章  程序设计基础
双击滚屏  关闭窗口
  2 . 3 面向对象的程序设计    

   2.3.1 关于面向对象方法
  2.3.2 面向对象方法的基本概念

  2.3.1 关于面向对象方法 

  今天,面向对象( object oriented )方法已经发展成为主流的软件开发方法。面向对象方法的形成同结构化方法一样,起源于实现语言,首先面向对象的程序设计语言开展研究,随之形成面向对象分析和设计方法。面向对象方法和技术经历 30 多年的研究和发展,已经越来越成熟和完善,应用也越来越深入和广泛。
   面向对象的软件开发方法在 20 世纪 60 年代后期首次提出,以 60 年代末挪威奥斯陆大学和挪威计算中心共同研制的 SIMULA 语言为标志,面向对象的基本要点首次在 SIMULA 语言中得到了表达和事项。后来一些著名的面向对象语言(如 Smalltalk 、 C++ 、 Java 、 Eiffel )的设计者都曾从 SIMULA 得到激发。随着 80 年代美国加州的 Xeror 研究中心推出 Smalltalk 语言和环境,使面向对象程序设计方法得到比较完善的事项。 Smalltalk-80 等一系列描述能力较强、执行效率较高的面向对象编程语言的出现,标志着面向对象的方法于技术开始走向实用。
   面向对象方法的本质,就是主张从客观世界固有的事物出发来构造系统,提倡用人类在现实生活中常用的思维方法来认识、理解和描述客观事物,强调最终建立的系统能够影射问题域,也就是说,系统中的对象以及对象之间的关系能够如实反映问题域中固有事物及其关系。
   面向对象程序方法之所以日益受到人民的重视和应用,成为流行的软件开发方法,是源于面向对象方法的以下主要优点。
   1. 与人类习惯的思维方法一致
   传统的程序设计方法是面向过程的,其核心方法是以算法为核心,把数据和过程作为相互独立的部分,数据代表问题空间中的课题,程序则用于处理这些数据,在计算机内部数据和程序是分开存放的,这样的做法往往会发生使用错误的数据调用正确的程序模块的情况。其原因是,传统的程序设计方法忽略了数据和操作之间的内在联系,用这种方法设计出来的软件系统其解空间与问题空间不一致,使人感到难于理解。实际上,用计算机解决的问题都是现实世界中的问题,这些问题无非由一些相互间存在一定联系的事物所组成,每个具体的事物都具有行为和属性两方面的特征。因此,把描述事物静态属性的数据结构和表示事物动态行为的操作防在一起构成一个整体,才能完整、自然地表示客观世界中的实体。
   面向对象方法和技术以对象为核心。对象是由数据和容许的操作组成的封装体,与客观实体有直接对应关系。对象之间通过传递消息互相联系,以模拟现实世界中不同事物彼此之间的联系。
   面向对象的设计方法与传统的面向过程的方法有本质不同,这种方法的基本原理是,使用现实世界的概念抽象地思考问题从而自然地解决问题。它强调模拟现实世界中的概念而不强调算法,它鼓励开发者在软件开发的绝大部分过程中都用应用领域的概念去思考。
   2. 稳定性好
   面向对象方法基于构造问题领域的对象模型,以对象为中心构造软件系统。它的基本作法是用对象模拟问题领域中的试题,以对象间的联系刻画实体间的联系。因为面向对象的软件系统的结构是根据问题领域的模型建立起来的,而不是基于对系统应完成的功能的分解,所以,当对系统的功能需求变化时并不会引起软件结构的整体变化,往往仅需要作一些局部性的修改。由于现实世界中的实体是相对稳定的,因此,以对象为中心构造的软件系统也是比较稳定的。而传统的软件开发方法以算法为核心,开发过程基于功能分析和功能分解。用传统方法所建立起来的软件系统的结构紧密地依赖于系统所要完成的功能,当功能需求发生变化时将引起软件结构的整体修改。事实上,用户需求变化大部分是针对功能的,因此,这样的软件系统是不稳定的。
   3. 可重用性好
   软件重用是指在不同的软件开发过程中重复使用相同或相似软件元素的过程。重用是提高软件生产率的最主要的方法。
   传统的软件重用技术是利用标准函数库,也就是试图用标准函数库中的函数作为“预制件”来建造新的软件系统。但是,标准函数缺乏必要的“柔性”,不能适应不同应用场合的不同需要,并不是理想的可重用的软件成分。实际的库函数往往仅提供最基本、最常用的功能,在开发一个新的系统时,通常多数函数是开发者自己编写的,甚至绝大多数函数都是新编的。
   使用传统方法学开发软件时,人们强调的是功能抽象,认为具有功能内聚性的模块是理想的模块,也就是说,如果一贯模块完成一个且只完成一个相对独立的子功能,那么这个模块就是理想的可重用,而且这样的模块也跟容易维护。基于这种认识,通常尽量把标准函数库中的函数做成功能内聚的。但是,事实上具有功能内聚性的模块并不是自含的和独立的,相反,它必须在数据上运行。如果要重用这样的模块,则相应的数据也必须重用。如果新产品中的数据与最初产品中的数据不同,则要么修改数据要么修改这个模块。
   事实上,离开了操作数据便无法处理,而脱离了数据的操作也是毫无意义的,我们应该对数据和草同样重视。在面向对象的方法中所使用的对象,其数据和操作是作为平等伙伴出现的。因此,对象具有很强的自含性,此外,对象所固有的封装性,使得对象的内部实现与外界隔离,具有较强的独立性。由此可见,对象提供了比较理想的模块化的机制和比较理想的可重用的软件成分。
   面向对象的软件开发技术在利用可重用的软件成分构造新的系统软件的时候,有很大的灵活性。有两种方法可以使用一个对象类:一种方法是创建该类的实例,从而直接使用它;另一种方法是从它派生出一个满足当前需要的新类。继承性机制使得子类不仅可以重用其父类的数据结构和程序代码,而且可以在父类代码的基础上方便地修改和扩充,这种修改并不影响对原有类的使用。可见,面向对象的软件开发技术所实现的可重用性是自然和准确的。
   4. 易于开发大型软件产品
   当开发大型软件时,组织开发人员的方法不恰当往往是出现问题的主要原因。用面向对象范型开发软件时,可以把一个大型产品看作是一系列本质上相互独立的小产品来处理,这就不仅降低了开发的技术难度,而且也使得对开发工作的管理变的更容易。这就好似为什么对于大型产品来说,面向对象范型优于结构化范型的原因之一。许多软件开发公司的经验都表明,当把面向对象技术用于大型软件开发时,软件成本明显地降低了,软件的整体质量提高了。
   5. 可维护性好
   用传统的方法开发和面向过程的方法开发出来的软件很难维护,是长期困扰人们的一个严重问题,是软件危机的突出表现。
   由于下述因素的存在,使得面向对象的方法开发的软件可维护性好。
   ( 1 )用面向对象的方法开发的软件稳定性比较好。
   如前所述,当对软件的功能或性能的要求发生变化时,通常不会引起软件的整体变化,往往只需对局部做一些修改。由于软件的改动较小且限于局部,自然比较容易实现。
   ( 2 )用面向对象的方法开发的软件比较容易修改。
   在面向对象方法中,核心是类(对象),它具有理想的模块机制,独立性好,修改一个类通常很少会牵扯到其他类。如果仅修改一个类的内部实现部分(私有数据成员或成员函数算法),而不修改该类的对外接口,则可以完全不影响软件的其他部分。
   面向对象技术特有的继承机制,使得对所开发的软件的修改和扩充比较容易实现,通常只需从已有类派生出一些新类,无需修改软件原有成分。
   面向对象技术的多态机制,使得当扩充软件功能时对原有代码的修改进一步减少,需要增加新代码也比较少。
   ( 3 )用面向对象的方法开发的软件比较容易理解。
   在维护已有软件的时候,首先需要对原有软件与此次修改有关的部分有深入理解,才能正确完成维护工作。传统软件之所以难于维护,在很大程度上是因为修改所涉及的部分分散在软件的各个地方,需要了解的面很广,内容很多,而且传统软件的解空间与问题空间的结构很不一致,更增加了理解原有软件的难度和工作量。
   面向对象的技术符合人们习惯的思维方式,用这种方法所建立的软件系统的结构与问题空间的结构基本一致。因此,面向对象的软件系统比较容易理解。
   对面向对象软件系统进行修改和扩充,通常是通过在原有类的基础上派生出一些新类来实现。由于对象类有很强的独立性,当派生新类的时候通常不需要详细了解基类中操作的实现算法。因此,了解原有系统的工作量可以大幅度降低。
   ( 4 )易于测试和调试
   为了保证软件的质量,对软件进行维护之后必须进行必要的测试,以确保要求修改或扩充的功能已正确的实现了,而且没有影响到软件未修改的部分。如果测试过程中发现了错误,还必须通过调试改正过来。显然,软件是否易于测试和调试,是影响软件可维护性的一个重要因素。
   对用面向对象的方法开发的软件进行维护,往往是通过从已有类派生出一些新类来实现。因此,维护后的测试和调试工作也主要围绕这些新派生出来的类进行。类是独立性很强的模块,向类的实例发消息后即可运行它,观察它是否能正确地完成相应的工作,因此对类的测试通常比较容易实现。

  2.3.2 面向对象方法的基本概念

  关于面向对象方法,对其概念有许多不同的看法和定义,但是都涵盖对象及对象属性与方法、类、继承、多态性几个基本要素。下面分别介绍面向对象方法中这几个重要的基本概念,这些概念是理解和使用面向对象方法的关键和基础。
   1. 对象( object )
   对象是面向对象方法中最基本的概念。对象可以用来表示客观世界中的任何实体,也就是说,应用领域中有意义的、与所要解决的问题有关系的任何事物都可以作为对象,它既可以是具体的物理实体的抽象,也可以是认为的概念,或者是任何有明确边界和意义的东西。例如,一个人、一家公司、一个窗口、贷款和借款等,都可以作为一个对象。总之,对象是对问题域中某个实体的抽象,设立某个对象就反映了软件系统保存有关它的信息并具有与它进行交互的能力。
   面向对象的程序设计方法中涉及的对象是系统中用来描述客观事物的一个实体,是构成系统的一个基本单位,它由一组表示静态特征的属性和它可执行的一组操作组成。
   例如,一辆汽车是一个对象,它包含了汽车的属性(如颜色、型号、载重量等)及其操作(如启动、刹车等)。一个窗口是一个对象,它包含了窗口的属性(如大小、颜色、位置等)及其操作(如打开、关闭等)。
   客观世界中的实体通常都既有静态的属性,有具有动态的行为,因此,面向对象方法学中的对象是由描述该对象属性的数据以及可以对这些数据施加的所以操作封装在一起构成的统一体。对象可以做的操作表示它的动态行为,在面向对象分析和面向对象设计中,通常把对象的操作也称为方法或服务。
   属性即对象所包含的信息,它在设计对象时确定,一般只能通过执行对象的操作来改变。如对象 Person 的属性有姓名、年龄、体重等。不同对象的同一属性可以具有相同或不同的属性值。如张三的年龄为 19 ,李四的年龄为 20 。张三、李四是两个不同的对象,他们共同的属性“年龄”的值不同。要注意的是,属性值应该指的是纯粹的数据值,而不能指对象。
   操作描述了对象执行的功能,若通过消息传递,还可以为其他对象使用。操作的过程对外是封闭的,即用户只能看到这一操作实施后的结果。这相当于实现已经设计好的各种过程,只需要调用就可以了,用户不必关心这一过程是如何编写的。事实上,这个过程已经封装在对象中,用户也看不到,即是对象的封装性。
   对象有如下一些基本特点:
   •  表示惟一性。指对象是可区分的,并且由对象的内在本质来区分,而不是通过描述来区分。
   •  分类性:指可以将具有相同属性和操作的对象抽象成类。
   •  多态性:指同一个操作可以是不同对象的行为。
   •  封装性:从外面看只能看到对象的外部特征,即只需知道数据的取值范围和可以对该数据施加的操作,根本无需知道数据的具体结构以及实现操作的算法。对象的内部,即处理能力的实行和内部状态,对外是不可见的。从外面不能直接使用对象的处理能力,也不能直接修改其内部状态,对象的内部状态只能由其自身改变。
   •  模块独立性较好。对象是面向对象的软件的基本模块,它是由数据及可以对这些数据施加的操作所组成的统一体,而且对象是以数据为中心的,操作围绕对其数据所需做的数据来处理设置,没有无关的操作。从模块的独立性考虑,对象内部各种元素彼此结合得很紧密,内聚性很强。
   2. 类( Class )和实例( Instance )
   将属性、操作相似的对象归为类,也就是说,类是具有共同属性、共同方法的对象的集合。所以,类是对象的抽象,它描述了属于该对象类型所有对象的性质,而一个对象则是其对应类的一个实例。
   要注意的是,当使用“对象”这个术语时,既可以指一个具体的对象,也可以泛指一般的对象,但是,当使用“实例”这个术语时,必然指的是一个具体的对象。
   例如: Integer 是一个整型类,它描述了所以整数的性质。因此任何整数都是整数类的对象,而一个具体的整数“ 123 ” 是类 Integer 的一个实例。
   由类的定义可知,类是关于对象性质的描述,它同对象一样,包括一组数据属性和数据上的一组合法操作。例如,一个面向对象的图形程序在屏幕左下角显示一个半径 3cm 的红颜色的圆,在屏幕中部显示一个半径 4cm 的绿颜色的圆,在屏幕右上角显示一个半径 1cm 的黄颜色的圆。这三个圆心位置、半径大小和颜色均不相同的圆,是三个不同的对象。但是,它们都有相同的属性(圆心坐标、半径、颜色)和相同的操作(显示自己、放大缩小半径、在屏幕上移动位置,等等)。因此,他们是同一类事物,可以用“ Circle 类”来定义。
   3 .消息( Message )
   面向对象的世界是通过对象与对象间彼此的相互合作来推动的,对象间的这种相互合作需要一个机制协助进行,这样的机制称为“消息”。消息是一个实例与另一个实例之间传递的信息,它请求对象执行某一处理或回答某一要求的信息,它统一了数据流和控制流。消息的使用类似于函数调用,消息中指定了某一个实例,一个操作名和一个参数表(可空)。接受消息的实例执行消息中指定的操作,并将形式参数与参数表中相应的值结合起来。消息传递过程中,由发送消息的对象(发送对象)的触发操作产生输出结果,作为消息传送至接受消息的对象(接受对象),引发接受消息的对象一系列的操作。所传送的消息实质上是接受对象所具有的操作 / 方法名称,有时还包括相应参数,图 2.5 表示了消息传递的概念。
              
                         图2.5 消息传递示意图
  消息中只包含传递者的要求,它告诉接受者需要做哪些处理,但并不指示接受者应该怎样完成这些处理。消息完全由接受者解释,接受者独立决定采用什么方式完成所需的处理,发送者对接受者不起任何控制作用。一个对象能够接受不同形式、不同内容的多个消息;相同形式的消息可以送往不同的对象,不同的对象对于形式相同的消息可以有不同的解释,能够做出不同的反映。一个对象可以同时往多个对象传递信息,两个对象也可以同时向某个对象传递消息。
   例如,一个汽车对象具有“行使”这项操作,那么要让汽车以时速 50 公里行使的话,需传递给汽车对象“行使”及“时速 50 公里”的消息。
   通常,一个消息由下述三部分组成:
   •  接受消息的对象的名称;
   •  消息标识符(也称为消息名);
   •  零个或多个参数。
   例如, MyCircle 是一个半径 4cm 、圆心位于( 100 , 200 )的 Circle 类的对象,也就是 Circle 类的一个实例,当要求它以绿颜色在屏幕上显示自己时,在 C++ 语言中应该向它发下列消息:
   MyCircle.Show(GREEN) ;
   其中, MyCircle 是接受消息的对象的名字, Show 是消息名, Green 是消息的参数。
   4. 继承( Inheritance )
   继承是面向对象的方法的一个主要特征。继承是使用已有的类定义作为基础建立新类的定义技术。已有的类可当作基类来引用,则新类相应地可当作派生类来引用。
   广义地说,继承是指能够直接获得已有的性质和特征,而不必重复定义它们。
   面向对象软件技术的许多强有力的功能和突出的优点,都来源于把类组成一个层次结构的系统:一个类的上层可以有父类,下层可以有子类。这种层次结构系统的一个重要性质是继承性,一个类直接继承其父类的描述(数据和操作)或特性,子类自动地共享基类中定义的数据和方法。
   为了更深入、具体地理解继承性的含义,图 2.6 示出了实现继承机制的原理。
           
                         图2.6 实现继承机制的原理
  图中以 A 、 B 两个类为例,其中类 B 是从类 A 派生出来的子类,它除了具有自己定义的特性(数据和操作)之外,还从父类 A 继承特性。当创建类 A 的实例 a1 的时候, a1 以类 A 为样板建立实例变量。
   当创建类 B 的实例 b1 的时候, b1 既要 B 为样板建立实例变量,又要以 A 为样板建立实例变量, b1 所能执行的操作既有类 B 中定义饿方法,又有类 A 中定义的方法,这就是继承。
   继承具有传递性,如果类 C 继承类 B ,类 B 继承类 A ,则类 C 继承类 A 。因此,一个类实际上继承了它上层的全部基类的特性,也就是说,属于某类的对象除了具有该类所定义的特性外,还具有该类上层全部基类定义的特性。
   继承分为单继承与多重继承。单继承是指,一个类只允许有一个父类,即类等级为树型结构。多重继承是指,一个类允许有多个父类。多重继承的类可以组合多个父类的性质构成所需要的性质。因此,功能更强,使用更方便;但是,使用多重继承时要注意避免二义性。继承性的优点是,相似的对象可以共乡程序代码和数据结构,从而大大减少了程序中的冗余信息,提高软件的可重用性,便于软件修改维护。另外,继承性使得用户在开发新的应用系统时不必完全从零开始,可以继承原有相似系统的功能或者从类库中选取需要的类,再派生出新的类以实现所需要的功能。
   5. 多态性( Polymorphism )
   对象根据所接受的消息而做出动作,同样的消息被不同的对象接受时可导致完全不同的行动,该现象称为多态性。在面向对象的软件技术中,多态性是指子类对象可以像父类那样使用,同样的消息既可以发送给父类对象也可以发送给子类对象。
   例如,在两个类 Male (男性)和 Female (女性)都有一项属性为 Friend 。一个人的朋友必须属于类 Male 或 Female ,这是一个多态性的情况。因为, Friend 指向两个类之一的实例。如果 Tom 的朋友或者是 Mary 或者是 John ,类 Male 就不知道 Friend 应该与哪个类关联。这里参照量 Friend 必须是多态的,多态意味着可以关联不同的实例,而实例可以属于不同的类。
   多态机制不仅增加了面向对象软件系统的灵活性,进一步减少了信息冗余,而且显著提高了软件的可重用性和可扩充性。当扩充系统功能增加新的实体类型时,只需派生出与新类相应的新的子类,完全无需修改原有的程序代码,甚至不需要重新编译原有的程序。利用多态性,用户能够发送一般形式的消息,而将所有的实现细节都留给接受消息的对象。     

 
                             返回首页                     双击滚屏  关闭窗口
数学与信息科学学院 版权所有