
4.1 面向对象概述
面向对象编程(object oriented programming,OOP)是软件开发的一种新的方法,使用这种方法开发的软件具有易维护、可重用和可扩展等特性。
4.1.1 OOP的产生
计算机诞生以来,为适应程序不断增长的复杂程度,程序设计方法论发生了巨大的变化。例如,在计算机发展初期,程序设计是通过输入二进制机器指令来完成的。在程序仅限于几百条指令的情况下,这种方法是可接受的。随着程序规模的增长,人们发明了汇编语言,这样程序员就可以使用代表机器指令的符号表示法来处理大型的、复杂的程序。随着程序规模的继续增长,高级语言的引入为程序员提供了更多的工具,这些工具可以使他们能够处理更复杂的程序。
20世纪60年代诞生了结构化程序设计方法,Pascal和C语言是使用这种方法的语言。结构化编程采用了模块分解与功能抽象和自顶向下、分而治之的方法,从而有效地将一个较复杂的程序系统设计任务分解成许多易于控制和处理的子程序,便于开发和维护。但是由于在实际开发过程中需求会经常发生变化,因此,它不能很好地适应需求变化的开发过程。结构化程序设计是面向过程的。
面向对象程序设计是一种功能强大的设计方法。它吸收了结构化程序设计的思想精华,并且提出了一些新的概念。广义上讲,一个程序可以用两种方法组织:一是围绕代码(发生了什么);二是围绕数据(谁受了影响)。如果仅使用结构化程序设计技术,那么程序通常围绕代码来组织。
面向对象程序则以另一种方式工作,它们围绕数据来组织程序。在面向对象语言中,需要定义数据和作用于数据的操作。
4.1.2 面向对象的基本概念
为了理解Java面向对象的程序设计思想,这里简单介绍有关面向对象的基本概念。
1.对象
在现实世界中,对象(object)无处不在。人们身边存在的一切事物都是对象。例如,一个人、一辆汽车、一台电视机、一所学校甚至一个地球,这些都是对象。除了这些可以触及的事物是对象外,还有一些抽象的概念,如一次会议、一场足球比赛、一个账户等也都可以抽象为一个对象。
一个对象一般具有两方面的特征:状态和行为。状态用来描述对象的静态特征,行为用来描述对象的动态特征。
例如,一辆汽车可以用下面的特征描述:生产厂家、颜色、最高时速、出厂年份、价格等。汽车可以启动、加速、转弯和停止等,这些是汽车所具有的行为或者说施加在汽车上的操作。又如,一场足球比赛可以通过比赛时间、比赛地点、参加的球队和比赛结果等特性来描述。软件对象也是对现实世界对象的状态和行为的模拟,如软件中的窗口就是一个对象,它可以有自己的状态和行为。
通过上面的说明,可以给“对象”下一个定义,即对象是现实世界中的一个实体,它具有如下特征:有一个状态用来描述它的某些特征。有一组操作,每个操作决定对象的一种功能或行为。
因此,对象是其自身所具有的状态特征及可以对这些状态施加的操作结合在一起所构成的实体。一个对象可以非常简单,也可以非常复杂。复杂的对象往往是由若干个简单对象组合而成的。例如,一辆汽车就是由发动机、轮胎、车身等许多其他对象组成。
2.类
类(class)是面向对象系统中最重要的概念。在日常生活中经常提到类这个词,如人类、鱼类、鸟类等。类可以定义为具有相似特征和行为的对象的集合,如人类共同具有的区别于其他动物的特征有直立行走、使用工具、使用语言交流等。所有的事物都可以归到某类中。例如,汽车属于交通工具类,手机属于通信工具类。
属于某个类的一个具体的对象称为该类的一个实例(instance)。例如,我的汽车是汽车类的一个实例。实例与对象是同一个概念。
类与实例的关系是抽象与具体的关系。类是多个实例的综合抽象,实例是某个类的个体实物。
3.消息
对象与对象之间不是孤立的,它们之间存在着某种联系,这种联系是通过消息传递的。例如,开汽车就是人向汽车传递消息。
一个对象发送的消息包含三方面的内容:接收消息的对象;接收对象采用的方法(操作);方法所需要的参数。
4.1.3 面向对象基本特征
为支持面向对象的设计原理,所有OOP语言,包括Java在内,都有三个特性:封装性、继承性和多态性。
1.封装性
封装(encapsulation)就是把对象的状态(属性)和行为(方法)结合成一个独立的系统单位,并尽可能地隐藏对象的内部细节。例如,一辆汽车就是一个封装体,封装了汽车的状态和操作。
封装使一个对象形成两个部分:接口部分和实现部分。对用户来说,接口部分是可见的,而实现部分是不可见的。
封装提供了两种保护。首先封装可以保护对象,防止用户直接存取对象的内部细节;其次封装也保护了客户端,防止对象实现部分的改变可能产生的副作用,即实现部分的改变不会影响到客户端的改变。
在对象中,代码或数据对该对象来说都可以是私有的(private)或公有的(public)。私有代码和数据仅能被对象本身的其他部分访问,不能被该对象外的任何程序所访问。当代码或数据是公有的时,虽然它们定义在对象中,但程序的其他部分也可以访问。
2.继承性
继承(inheritance)的概念普遍存在于现实世界中。它是一个对象获得另一个对象属性的过程。继承之所以重要,是因为它支持层次结构类的概念。可以发现,在现实世界中,许多知识都是通过层次结构方式进行管理的。
例如,一个富士苹果是苹果类的一部分,而苹果又是水果类的一部分,水果类则是食物类的一部分。食物类具有的某些特性(可食用,有营养)也适用于它的子类水果。除了这些特性以外,水果类还具有与其他食物不同的特性(多汁、味甜等)。苹果类则定义了属于苹果的特性(长在树上,属于非热带植物)。图4-1给出了食物及其子类的继承关系。

图4-1 食物类及子类层次
如果不使用层次结构,那么对象就不得不明确定义自己的特征。如果使用继承,那么对象就只需定义自己特有的属性就可以了,至于基本的属性则可以从父类继承。
继承性体现了类之间的是一种(IS-A)关系。类之间的关系还有组合、关联等。
3.多态性
多态性(polymorphism)是面向对象编程语言的一个重要特性。所谓多态,是指一个程序中相同的名字表示不同含义的情况。面向对象程序中的多态有多种情况。在简单的情况下,在同一个类中定义了多个名称相同的方法,即方法重载;另一种情况是子类中定义的与父类中的方法同名的方法,即方法覆盖。这两种情况都称为多态,且前者称为静态多态,后者称为动态多态。有关Java语言的多态性请参考本书7.5节的介绍。
4.1.4 OOP的优势
OOP完全不同于传统的面向过程的程序设计,极大地降低了软件开发的难度,使编程就像搭积木一样简单,OOP的优势包括代码易维护、可重用以及可扩展。OOP的好处是实实在在的,这正是大多数现代编程语言均是面向对象的原因。
1.易维护(maintainability)
现代的软件规模往往都十分巨大。一个系统有上百万行的代码已是很平常的。C++之父Bjarne Stroustrup曾经说过,当一个系统变得越来越大时,就会给开发者带来很多问题。其原因在于,大型程序的各个部分之间是相互依赖的。当修改程序的某个部分时可能会影响到其他部分,而这种影响是不能轻易被发现的。采用OOP方法就可以很容易地使程序模块化,这种模块化极大地减少了维护的问题。在OOP中,模块是可以继承的,因为类(对象的模板)本身就是一个模块。好的设计应该允许类包含类似的功能性和有关数据。OOP中经常用到的一个术语是耦合,它表示两个模块之间的关联程度。不同部分之间的松耦合会使代码更容易实现重用,这是OOP的另一个优势。
2.可重用(resusability)
可重用是指之前写好的代码可以被代码的创建者或需要该代码功能的其他人重用。因此,OOP语言通常提供一些预先设计好的类库供开发员使用。Java就提供了几百个类库或API(应用编程接口),这些都是经过精心设计和测试的。用户也可以编写或发布自己的类库。支持编程平台中的可重用性,这是十分吸引人的,因为它可以极大地缩短开发时间。
可重用性不仅适用于重用类和其他类型的代码,在OOP系统中设计应用程序时,针对OOP设计问题的解决方案也可以重用,这些解决方案称为设计模式,为了便于使用,每种设计模式都有一个名字。
3.可扩展(extensibility)
可扩展是指一种软件在投入使用之后,其功能可以被扩展或增强。在OOP中,可扩展性主要通过继承来实现。可以扩展现有的类,对它添加一些方法和数据,或修改不适当方法的行为。如果某个基本功能需要多次使用,但又不想让类提供太具体的功能,就可以设计一个泛型类,以后可以对它进行扩展,使它能够提供特定于某个应用程序的功能。
OO技术主要包括下面三个领域:面向对象分析(object oriented analysis,OOA)、面向对象设计(object oriented design,OOD)和面向对象编程(object oriented programming,OOP)。
Java与面向对象方法是密不可分的,所有的Java程序至少在某种程度上都是面向对象的。因为OOP对Java的重要性,所以在开始编写哪怕是一个很简单的Java程序之前,理解OOP的基本原理都是非常有用的。