返回 登录
0

Java的面向对象编程

什么是面向对象

在目前的软件开发领域有两种主流的开发方法,分别是结构化开发方法和面向对象开发方法。早期的编程语言如C、Basic、Pascal等都是结构化编程语言,随着软件开发技术的逐渐发展,人们发现面向对象可以提供更好的可重用性、可扩展性和可维护性,于是催生了大量的面向对象的编程语言,如C++、Java、C#和Ruby等。

面向对象程序设计即OOP,是Object-Oriented Programming的缩写。面向对象编程技术是一种起源于20世纪60年代的Simula语言,其自身理论已经十分完善,并被多种面向对象程序设计语言(Object-Oriented Programming Langunianling,OOPL)实现。由于很多原因,国内大部分程序设计人员并没有很深的OOP以及OOPL理论,很多人从一开始学习到工作很多年都只是接触到C/C++、Java等静态类型语言,而对纯粹的OOP思想以及动态类型语言知之甚少。

对象的产生通常基于两种基本方式,分别是以原型对象为基础产生新对象和以类为基础产生新对象。

1.基于原型

原型模型是以一个有代表性的对象为基础来产生各种新的对象,并由此继续产生更符合实际应用的对象。而原型—委托也是OOP中的对象抽象,是代码共享机制中的一种。

2.基于类

一个类提供了一个或多个对象的通用性描叙。从形式化的观点看,类与类型有关,因此,一个类相当于是从该类中产生的实例的集合。

Java的面向对象编程

面向对象编程方法学是Java编程的指导思想。在使用Java进行编程时,应该首先利用对象建模技术(OMT)来分析目标问题,抽象出相关对象的共性,对它们进行分类,并分析各类之间的关系;然后再用类来描述同一类对象,归纳出类之间的关系。Coad和Yourdon在对象建模技术、面向对象编程和知识库系统的基础之上设计了一整套面向对象的方法,具体来说分为面向对象分析(OOA)和面向对象设计(OOD)。对象建模技术、面向对象分析和面向对象设计共同构成了系统设计的过程,如图1所示。
图片描述
图1 系统设计处理流程

UML统一建模语言

在进行对象建模、面向对象分析和设计的过程中,需要使用建模语言来描述分析的过程和结果。统一建模语言即UML,是Unified Modeling Langunianling的缩写。UML是为了实现上述目标而设计的一种标准通用的设计语言。

1.UML图的类型

UML为我们提供了多种类型的模型描述图,当在某种给定的方法学中使用这些图时,人们就能更容易理解和交流设计思想。UML图可以分为如下3种类型。

(1)静态图。

静态图即Static Diagram,其功能是描述了不发生任何变化的软件元素的逻辑结构,描绘了类、对象和数据结构及其存在于它们之间的关系。

(2)动态图。

动态图即Dynamic Diagram,其功能是展示软件实体在运行期间的的变化,主要描绘了执行流程、实体改变状态的方式。

(3)物理图。

物理图即Physical Diagram,其功能是显示软件实体不变化的物理结构,主要用来描绘库文件、字节文件和数据文件等,以及存在于它们之间的相互关系。

2.类图和对象图

在Java中,通常使用类图和对象图来表示项目内程序类的结构和各元素间的对应关系。在下面的内容中,将简要介绍类图和对象图的基本知识。

(1)类图。

类图表示不同的实体间的相互关系,显示了系统的静态结构。类图可用于表示逻辑类,逻辑类通常是指事物的种类,比如球队、电影之类的抽象描述。类图还可以用于表示实现类,实现类就是程序员要编写的类。实现类图与逻辑类图可能会用来描述一些相同的类。然而,实现类图与逻辑类图不会使用相同的描述属性。

类图通常用矩形表示,并在矩形内将类分为3个部分。其中最上面的部分显示类的名称,中间部分显示类的属性,最下面的部分显示类的方法,例如图2所示的格式。
图片描述
图2 典型类图结构

注意

在现实应用中,最常用、最简单的类图就是一个在里面显示了类名的长方形。在大多数的UML中,多数类只要有一个能够清楚表达的命名就可以了。

在类名部分还可以显示类的构造类型,类的构造型在双角括符号“« »”之间指定,并放在类的名称上面。常见的构造类型包括如下3类。

实现类:直接显示类的名称。
接口:在类名上方的双角括符号“« »”内显示。
工具类:在类名上方的双角括符号“« »”内显示。
如果类名用斜体表示,或者在类名下面,则表示这个类是一个抽象类。

在属性和方法的前面可以用修饰符“+”或“-”,其功能是表示属性或方法的作用域,具体说明如下所示。

修饰符“-”:表示属性或方法是私有的(private)。
修饰符“#”:表示属性或方法是保护的(protected)。
修饰符“+”:表示属性或方法是公用的(public)。
通常在类的属性或方法参数名称的冒号后,显示了属性的类型或方法的参数的类型。方法的返回值类型显示在方法后面的冒号之后。

例如图3显示了一个Lei类的类图结构。
图片描述
图3 Lei类的类图结构

(2)对象图。

对象图的功能是用来表示类的实例化对象。通常用一个两层的矩形结构来表示对象图,其中上层标识对象名和类名,下层标识对象的实例化属性值。例如在下面的代码中,创建了一个Lei类的对象mm。

Lei mm = new Lei("mm", 'F', 24);

上述mm对象的对象图如图4所示。
图片描述
图4 对象图示例

在同一个应用项目中,类之间可能存在如下多种类别的相互关系。

继承:即inheritance,是指一个类从其父类派生而来,继承了父类的属性和方法。基于类的继承叫做一般化(generalization),基于接口的继承,叫做实现(realization)。
关联:即association,类之间的关联大多用来表示变量实例持有对其他对象的引用,这种关系是半永久的,并没有包含关系。
依赖:即dependency,是不同类实例之间的暂时相互关系。
聚合:即aggregation,是关联的一种特殊形式,代表着一种整体和部分的关系。并且里面的部分可以作为其他整体的部分,而部分和整体之间也没有生命期的依赖。
组合:即composition,是聚合的一种特殊形式。组合的关联性比聚合更强,而部分只能作为唯一的一个整体的部分,而且部分的生命周期依赖于整体的生命周期。
UML是一种设计语言,它的目的不是表现细节,而是表现结构,仅仅展示必要的细节。所以UML不可能与源代码一一对应,只是在结构上存在了某种对应关系。

3.序列图和状态图

除了前面介绍的类图和对象图外,在Java中还可以使用序列图和状态图来表示项目内程序类的结构和各元素间的对应关系。在下面的内容中,将对序列图和状态图的基本知识进行简要介绍。

(1)序列图。

序列图显示具体用例(或用例的一部分)的详细流程,它不但显示了流程中不同对象之间的交互关系,而且还可以很详细地显示对不同对象的各种调用。在序列图中有如下两个维度。

垂直维度:以发生的时间顺序显示消息/调用的序列。
水平维度:显示对象实例之间的交互。
对象之间的交互存在如下5种关系。

调用:即call,一个对象调用另一个对象(或本身)的方法。
返回:即return,返回一个值作为方法调用的结果。
发送:即send,一个对象给另一个对象(或本身)异步发送一个消息。
创建:即create,一个对象实例化另一个对象。
销毁:即destroy,一个对象销毁另一个对象(或本身)。
绘制序列图的方法非常简单,通常用图顶部的框表示类的实例对象,框中的类实例名称和类名称之间用空格/冒号/空格来分隔。如果某个类实例向另一个类实例发送了处理消息,则绘制一条具有指向接收类实例的开箭头的连线,并把处理的名称放在连线上面。对于某些特别重要的消息,可以绘制一条具有指向发起类实例的开箭头的虚线,将返回值标注在虚线上。有助于序列图的阅读。

(2)状态图。

状态图表示某个类所处的不同状态和该类的状态转换信息。每个类都有状态,但不是每个类都应该有一个状态图。只有当行为的改变和状态有关时才创建状态图。一般只描述在系统活动期间具有3个或更多潜在状态的类的状态图。

状态图中的符号集包括如下5个基本元素。

初始起点:使用实心圆来绘制。
状态转换:使用带箭头的线段来绘制。
当前状态:使用圆角矩形来绘制。
判断点:使用空心圆来绘制。
一个或者多个终止点:使用内部包含实心圆的圆来绘制。
在绘制状态图时,首先需要绘制起点和一条指向该类的初始状态的转换线段。状态本身可以在图上的任意位置绘制,然后只需使用状态转换线条将它们连接起来。

对象建模技术

对象建模技术源于通用电气公司的一套系统开发技术,是以面向对象的思想为基础,通过对问题进行抽象而构造出一组相关的模型。通过对象建模技术,可以全面地描述问题领域的结构。对象建模技术把分析时收集到的信息构造在如下3类模型中。

功能模型:功能模型定义系统做什么。
对象模型:对象模型定义系统对谁做。
动态模型:动态模型定义系统如何做。
通过上述3个模型,可以从不同的角度对系统进行描述,首先分别着重于系统的某个侧面,然后整体组合起来构成对系统的完整描述。

1.功能模型

功能模型的功能是实现系统内部数据的传送和处理。功能模型能够说明,从输入数据能够计算出什么样的输出数据,但是,没有考虑参加计算的数据按什么时序来执行。功能模型由多个数据流图组成,它们指明从外部输入,通过操作和内部存储,直到外部输出的整个数据流情况。功能模型还包括了对象模型内部数据间的限制。功能模型中的数据流图往往形成一个层次结构,一个数据流图的过程可以由下一层的数据流图作进一步的说明。UML中通常使用用例图和活动图来描述功能模型。

建立功能模型的主要步骤如下所示。

(1)确定输入和输出值。

(2)用数据流图表示功能的依赖性。

(3)具体说明每个具体功能。

(4)确定限制。

(5)确定功能优化的准则。

上述操作的具体实现流程如图5所示。
图片描述
图5 功能模型处理流程

2.对象模型

对象模型的功能是描述系统的静态结构,包括类和对象,它们的属性和操作,以及它们之间的关系。构造对象模型的主要目的是,发掘与项目应用密切相关的概念。对象模型用包含对象和对象之间关系的图来表示,在UML中通常使用类图和对象图来描述对象模型。

使用OMT建立对象模型的主要步骤如下所示。

(1)确定对象类。

(2)定义数据词典,并利用它来描述类的属性和类之间的关系。

(3)用继承来组织和简化类的结构和类之间的关系。

(4)测试访问路径。

(5)根据对象之间的关系和对象的功能将对象分组建立模块。

上述操作的具体实现流程如图6所示。
图片描述
图6 对象模型处理流程

3.动态模型

动态模型主要用于控制系统的逻辑,考察在任何时候对象及其关系的改变,描述这些涉及时序和改变的状态。通常使用状态图和事件跟踪图来描述动态模型。

状态图是状态和事件以及它们之间的关系所形成的网络,侧重于描述每一类对象的动态行为。而事件跟踪图则侧重于说明系统执行过程中的一个特点场景,描述完成系统某个功能的一个事件序列。

对象到对象的单个消息叫做一个事件。在系统的一个特定环境下发生的一系列事件叫做一个场景。场景通常起始于一个系统外部的输入事件,结束于一个系统外部的输出事件。在一个场景中,一系列事件和交换事件的对象都可以放在一个事件跟踪图中表示。UML使用状态图和序列图来描述动态模型,序列图对应于事件跟踪图。

建立动态模型的主要步骤如下所示。

(1)预制典型的交互序列场景。

(2)确定对象之间的事件,为每个场景建立事件跟踪图。

(3)为每个系统预制一个事件流图。

(4)为具有重要动态行为的类建立状态图。

(5)检验不同状态图中共享的事件的一致性和完整性。

上述操作的具体实现流程如图7所示。
图片描述
图7 动态模型处理流程

面向对象分析

面向对象分析属于软件开发过程中的问题定义阶段。传统的系统分析产生一组面向过程的文档,定义目标系统的功能;面向对象分析则产生一种描述系统功能和问题领域的基本特征的综合文档。

1.面向对象分析的原则

Java中面向对象的分析需要遵循下面的原则。

(1)抽象。

从许多事物中舍弃个别的、非本质的特征,抽取共同的、本质性的特征,这就是抽象。抽象是形成概念的必要手段。抽象原则具有如下两点意义。

尽管问题域中的事物是很复杂的,但是分析员并不需要了解和描述它们的一切,只需要分析研究其中与系统目标有关的事物及其本质性特征。
通过舍弃个体事物在细节上的差异,抽取其共同特征而得到一批事物的抽象概念。
抽象是面向对象方法中使用最为广泛的原则,抽象原则包括过程抽象和数据抽象两个方面。

过程抽象:任何一个完成确定功能的操作序列,使用者都可以把它看成一个单一的实体,尽管实际上它可能是由一系列更低级的操作完成的。
数据抽象:根据施加于数据之上的操作来定义数据类型,并限定数据的值只能由这些操作来修改和观察。数据抽象是面向对象分析的核心原则。它强调把数据(属性)和操作(服务)结合为一个不可分的对象,对象的外部只需要知道它做什么,而不必知道它如何做。
(2)封装。

封装就是把对象的属性和服务结合为一个不可分的系统单位,并尽可能隐蔽对象的内部细节。

(3)继承。

特殊类的对象拥有的其一般类的全部属性与服务,这是特殊类对一般类的继承。在面向对象分析中运用继承原则,就是在每个由一般类和特殊类形成的结构中,把一般类的对象实例和所有特殊类的对象实例都共同具有的属性和服务,一次性地在一般类中进行显式定义。在特殊类中不再重复地定义一般类中已定义的东西,但是在语义上,特殊类却自动地、隐含地拥有它的一般类(以及所有更上层的一般类)中定义的全部属性和服务。继承原则的好处是:使系统模型比较清晰。

(4)分类。

分类就是把具有相同属性和服务的对象划分为一类,用类作为这些对象的抽象描述。分类原则实际上是抽象原则运用于对象描述时的一种表现形式。

(5)聚合。

聚合的原则是:把一个复杂的事物看成若干比较简单的事物的组装体,从而简化对复杂事物的描述。

(6)关联。

通过一个事物联想到另外的事物,能使人发生联想的原因是事物之间确实存在着某些联系。

(7)消息通信。

这一原则要求对象之间只能通过消息进行通信,而不允许在对象之外直接地存取对象内部的属性。通过消息进行通信是由于封装原则引起的。在OOA中要求用消息连接表示出对象之间的动态联系。

(8)粒度控制。

考虑某部分的细节时暂时撇开其余的部分,这就是粒度控制原则。

2.面向对象分析的阶段

面向对象分析的过程分为两个阶段,分别是问题领域分析和应用分析,这两个阶段的具体说明如下所示。

(1)问题领域分析阶段。

问题领域分析是软件开发的基本组成部分,目的是使开发人员了解问题领域的结构,建立大致的系统实现环境。问题领域分析给出一组抽象概念作为特定系统需求开发的参考。问题领域分析实际上是一种学习过程。软件开发人员在这个阶段应该尽可能地理解当前系统中与应用有关的知识,放宽考虑的范围,尽可能地标识与应用有关的概念。有了广泛的问题领域知识,涉及具体的应用时,就可以更快地进入状态,掌握应用的核心知识。而且,在用户改变对目标系统的需求时,广泛的分析可以帮助我们预测出目标系统在哪些方面会发生哪些变化。在分析过程中,应该标识出系统的基本概念(对象、类、方法、关系等)、识别问题领域的特征,并把这些概念集成到问题领域的模型中。问题领域的模型必须包含概念之间的关系,以及每个概念的全部信息。标识出来的相关概念应该根据信息内容来有机地融合到问题领域的综合视图中。

(2)应用分析阶段。

应用分析是依据在问题领域分析时建立起来的问题领域模型来进行的。应用分析时,把问题领域模型用于当前特定的应用之中。首先,通过收集到的用户信息来对问题领域进行取舍,把用户需求作为限制条件来使用,以缩减问题领域的信息量。因此,问题领域分析的视野大小直接影响到应用分析保留的信息量。一般来说,问题领域分析阶段产生的模型并不需要用程序设计语言来表示,而应用分析阶段产生的影响条件则需要用某种程序设计语言来表示。模型识别的要求可以针对一个应用,也可以针对多个应用。通常我们着重考虑两个方面,即应用视图和类视图。在类视图中,必须对每个类的属性和操作进行细化,并表示出类之间的相互作用关系。

3.面向对象分析的具体目标

面向对象分析需要完成如下两个目标。

(1)形式化地说明所面对的应用问题,最终形成软件系统基本构成的对象,以及系统所必须遵从的、由应用环境所决定的规则和约束条件。

(2)明确地规定构成系统的对象如何协同工作和完成指定的功能。

通过面向对象分析所建立的系统模型是以概念为中心的,因此称为概念模型。概念模型由一组相关的类组成。面向对象分析可以通过自顶向下地逐层分解来建立系统模型,也可以自底向上地从已经定义的类出发,逐步构造新的类。

概念模型的构造和评审由如下5个层次构成。

类和对象层。
属性层。
服务层。
结构层。
主题层。
上述5个层次不是构成软件系统的层次,而是分析过程中的层次。当5个层次的工作全部完成时,面向对象分析的任务也就完成了。

注意

在实际编程操作中,面向对象分析的目标是得出问题领域的功能模型、对象模型和动态模型,并用相应的UML图将它们表示出来。

面向对象设计

经过前面的分析处理后,接下来就可以进行具体设计了。面向对象设计的任务是对面向对象分析的结果进行规范化整理,以便能够被面向对象编程直接接受。在接下来的内容中,将简要介绍面向对象设计的基本知识。

1.面向对象设计概述

面向对象设计是一种软件设计方法,是一种工程化规范。面向对象设计中主要的操作如下所示。

确定需要的类。
给每个类提供一组完整的操作。
明确地使用继承来表现共同点。
所以说,面向对象设计就是一个根据需求决定所需的类、类的操作,以及类之间关联的过程。

从面向对象分析到面向对象设计是一个逐步扩充模型的过程。面向对象分析以实际问题为中心,可以不考虑与软件实现相关的任何问题,主要考虑“做什么”的问题;面向对象设计则是面向软件实现的实际开发活动,主要考虑“怎么做”的问题。

面向对象设计的目标是管理程序内部各部分的相互依赖关系。为了达到这个目标,面向对象设计要求将程序分成块,然后分别将各个块隐藏在接口(interface)的后面,让它们只通过接口相互交流。比如说,如果用面向对象设计的方法来设计一个客户端—服务器应用,那么服务器和客户端之间不应该有直接的依赖,而是应该让服务器的接口和客户端的接口相互依赖。

2.面向对象设计的原则

面向对象设计所要遵循的原则如下所示。

(1)模块化。

面向对象开发方法很自然地支持了把系统分解成模块的设计原则:对象就是模块。它是把数据结构和操作这些数据的方法紧密地结合在一起所构成的模块。

(2)抽象。

面向对象方法不仅支持过程抽象,而且支持数据抽象。

(3)信息隐藏。

在面向对象方法中,信息隐藏通过对象的封装性来实现。

(4)低联系。

在面向对象方法中,对象是最基本的模块,因此,联系主要指不同对象之间相互关联的紧密程度。低联系是设计的一个重要标准,因为这有助于使得系统中某一部分的变化对其他部分的影响降到最低。

3.面向对象设计的任务

面向对象设计有如下3个任务。

(1)对象定义规格的求精。

对于面向对象分析所抽象出来的对象、类,以及汇集的分析文档,面向对象设计需要有一个根据设计要求整理和求精的过程,使之更能符合面向对象编程的需要,具体实施如下。

根据面向对象的概念模型整理分析所确定的对象结构、属性、方法等内容,改正错误的内容,删去不必要和重复的内容等。
进行分类整理,以便于下一步数据库设计和程序处理模块设计的需要,整理的方法主要是进行归类,对类、对象、属性、方法和结构、主题进行归类。
(2)数据模型和数据库设计。

数据模型的设计需要确定类、对象属性的内容、消息连接的方式、系统访问、数据模型的方法等。最后,每个对象实例的数据都必须落实到面向对象的库结构模型中。

(3)优化。

面向对象设计的优化设计过程是从另一个角度对分析结果和处理业务过程的整理归纳,优化包括对象和结构的优化、抽象、集成。

4.面向对象设计的过程和步骤

面向对象设计的过程,是通过利用设计阶段中的4个层次来建立系统的问题领域、用户界面、任务管理和数据管理的过程。

(1)问题领域。

问题领域包括与我们所面对的应用问题直接相关的所有类和对象。主要是根据需求的变化来对面向对象分析阶段产生的模型中的类和对象、结构、属性和操作进行组合和分解,根据面向对象设计原则来增加必要的类、属性和关系。

(2)用户界面。

通常在面向对象分析阶段给出了所需的属性和操作,在面向对象设计阶段必须根据需求把交互的细节加入用户界面的设计中,包括有效的人机交互所必需的实际显示和输入。

用户界面部分的设计主要由以下7个方面组成。

用户分类。
描述人及其任务的脚本。
设计命令层。
设计详细的交互。
继续扩展用户界面原型。
设计人机交互类。
根据图形用户界面进行设计任务管理部分的设计。

(3)任务管理。

任务是进程的别称,是执行一系列活动的一段程序。当系统中有许多并发行为时,需要依照各个行为的协调和通信关系来划分各种任务,以简化并发行为的设计和编码。任务管理主要包括任务的选择和调整。

(4)数据管理。

数据管理提供了在数据管理系统中存储和检索对象的基本结构,包括对永久性数据的访问和管理。数据管理的方法主要有3种,分别是文件管理、关系数据库管理,以及面向对象的数据库管理。

Java的面向对象特性

Java是一门纯粹的面向对象的编程语言,完全支持封装、继承和多态这三大面向对象的基本特征。Java程序的组成单位就是类,不管什么规模的Java应用程序,都是由一个个类组成的。

1.一切皆为对象

在Java语言中,除了8个基本数据类型值之外都是对象,对象就是面向对象程序设计的中心。对象是人们要进行研究的任何事物,从最简单的数字到复杂的航空母舰等均是对象。对象不仅能表示具体的事物,而且还能表示抽象的规则、计划或事件。对象是具有状态的,一个对象用数据值来描述它的状态。Java通过为对象定义Field(以前常被称为属性,现在也称为字段)来描述对象的状态。对象也具有操作,这些操作可以改变对象的状态,对象的操作也被称为对象的行为,Java通过为对象定义方法来描述对象的行为。对象实现了数据和操作的结合,使数据和操作封装于对象的统一体中。对象是Java程序里的核心,所以,Java里的对象具有唯一性,每个对象都有一个标识来引用它,如果某个对象失去了标识,这个对象将变成垃圾,只能等着系统垃圾回收来回收它。Java语言不允许直接访问对象,而是通过对对象的引用来操作对象。

2.类和对象

具有相同或相似性质的一组对象的抽象就是类,类是抽象的、概念上的定义,是对一类事物的描述。对象是实际存在的该类事物的每个个体,因而也称实例(instance)。对象的抽象是类,类的具体化就是对象,也可以说类的实例是对象。类用来描述一系列对象,类会概述每个对象应包括的数据,类概述每个对象的行为特征。因此,我们可以把类理解成某种概念、定义,它规定了某类对象所共同具有的数据和行为特征。

Java语言使用关键字class来定义一个类,Java允许程序员自定义类。在Java中定义类时,可使用关键字Field来描述该类对象的数据,可使用方法来描述该类对象的行为特征。类的行为特主要是指属性和操作,具体说明如下所示。

Java中的类具有属性,它是对象状态的抽象,用数据结构来描述该类对象的共同数据特征。
Java中的类具有操作,它是对象行为的抽象,用操作名和实现该操作的方法来描述该类对象的共同行为。
在客观世界中有若干类,这些类之间有一定的结构关系。通常有如下两种主要的结构关系。

一般—特殊结构:也被称为分类结构,这种分类结构关系就是典型的继承关系,Java语言使用关键字extends来表示这种分类结构,Java的子类是一种特殊的父类。因此,这种“一般—特殊”结构关系其实是一种“is a”关系。
整体—部分结构:也被称为组装结构,这种分类关系就是典型的组合关系,Java语言通过在一个类里保存另一个对象的引用来实现这种组合关系,因此这种“整体—部分”结构关系其实是一种“has a”关系。
程序员在定义Java类之后,就可以使用关键字new来创建指定类的对象,每个类可以创建任意多个对象,多个对象的Field值可以不同,这表现为不同对象的数据存在差异。

评论