• 沒有找到結果。

面向对象

在文檔中 Code Complete 代码大全 (頁 110-114)

第七章 高级结构设计

7.3 面向对象

面向对象设计方法的特点是通过对实际问题的分析,从中抽象出对象,然后再用程序语言 来表现它,其过程主要是:识别对象中的子对象并识别出对于子对象的操作,然后再根据子对 象的操作开发出一个系统。面向对象设计是在程序中设计对象或模块的一种方法。在较低的程 度上说,它也是设计单个子程序的一种方法。

虽然有些鼓吹者把计算机历史划分为面向对象设计出现前阶段和面向对象设计出现后阶 段,但事实上面向对象设计与其它设计方法并不冲突。特别地,面向对象设计与结构化编程所 提供的低层次结构化并不是不兼容的,但它与高层次结构化的确不兼容。在更高的层次上,面 向对象设计方法在简单的功能性层次结构上,添加了类、群和非层次结构等新的概念。对这些 高层次的组合思想进行研究和标准化工作,将会使编程技术再向前产生一次飞跃。

在本书,对于面向对象设计的讨论是非常浅显的。与结构化设计方法相比,面向对象设计 的抽象化程度更高。本节着重论述的只是在较低层次上起作用的抽象方法,其中主要是在个别 语句、子程序和有限数量的子程序这个层次上的。这种设计方法相对来说也是一种新的设计理 论。它还没有完全成熟,关于这方面积累的设计经验也还不够丰富,但是,它是很有前途的。

7.3.1 关键思想

面向对象设计是建立在如下主张之上的,即:一个程序模型越是真实地反映了实际问题,

那么,由此产生出的程序质量越好,在多数情况下,关于项目的数据定义要比功能稳定得多,

因此应象面向对象设计一样,根据数据来进行设计,这可以使设计更稳定。对于现代编程来说,

面向对象设计中有许多思想是很重要的。

抽象

抽象所带来的主要好处是可以忽略掉无关紧要的细枝末节问题,而专注于重要的特性。绝 大多数现实世界中的对象都是抽象的,房屋是木材、钉子、玻璃、砖和水泥等的抽象,是把它 们组织起来的一种特殊形式。而木材本身,则又是纤维、细胞及某些矿物质的抽象,而细胞呢,

则又是各种各样的物质分子的抽象。

在建造房屋时,如果你从分子层次上与木材、钉子等打交道,是永远不可能建成房屋的。

同样,在建造一个软件系统时,如果总是在相当于分子的层次上工作,那是不可能建成软件系 统的。在面向对象设计中,你尽力创造出与解决真实问题某一部分抽象程度相同的编程抽象,

以便解决编程问题中的类似部分,而不是用编程语言实体来解决问题。

面向对象设计擅长使用抽象,但因为它所使用的“智力砖块”,要比结构化设计中功能方 法所使用的“智力砖块”大得多。在结构化设计中,抽象的单位是函数;而在面向对象设计中,

抽象的单位是对象。由于对象包括函数及受函数影响的数据,从而使得在比函数更高层次上对 问题进行处理成为可能。这种抽象能力使你可以在更高层次上对问题进行考虑,而且,不必把 神经绷得太紧,就可以一次考虑很多问题。

封装

封装是对抽象不存在地方的补充。如果抽象对你说“你应该在较高层次上看一个对象”,而 封装则会说“你只能在这个层次上看一个对象”。这事实上就是 6.2 节所述的信息隐蔽的重复。

你对于一个模块所知道的只是它让你知道的那些,别的什么也没有。

我们继续用房屋比拟来说明问题:封装是一个使你可以看到房屋的外表但不能走进去的办 法,当然,或许你可以透过窗户看到一小部分内部情况。在较为过时的语言中,信息隐蔽完全 是自愿的行为,因为大门上没有“禁止入内”的标志,房门没有上锁,窗户也是敞开的,而对 于 Ada 语言来说,信息隐蔽则是强制性的:门被牢牢地锁上了,窗户紧闭,而且警报系统也在 工作,你所看到的就是你所得到的,而且是你得到的一切。

模块化

面向对象设计中的模块与结构化设计中模块的含义是一致的。相联系的数据和功能被放 入模块,在理想情况下,模块是高度内聚而又松散耦合的。同信息隐蔽一样,当模块内部发生

变化时,其接口保持不变。

层次结构和继承性(inheritance)

在设计软件系统时,你经常可以发现两个之间非常相似,其差别非常小的对象。例如,在 一个会计系统中,你可能既要考虑正式雇员,也要考虑兼职雇员,与两种雇员相联系的绝大多 数数据都是相同的,但也有一小部分是不同的。在面向对象编程中,你可以定义一种广义雇员,

把正式雇员当作一种广义雇员,但二者之间稍有差别。把兼职雇员也看作一种与种类无关的广 义雇员,那么这种操作就按广义雇员模式进行。如果某种操作是与雇员种类有关的,那么就按 雇员种类不同,分别进行操作。

定义这种对象间的共同和不同点称为“继承性”,因为兼职和正式雇员都从广义雇员那里继 承了许多特点。

继承策略的好处是它与抽象的概念是一致的,抽象在不同层次的细节上与对象打交道。在 某一层次上调用某种分子;在下一个层次上调用纤维与植物细胞的组合,在最高层次上调用一 片木头。木头有某种特性(如你可以用锯子锯它或用斧头劈它),不管是松木还是加州红杉木,

它们有许多共同的特性,如同它们有不同特性一样。

在面向对象编程中,继承性简化了编程,因为你只要写一个通用子程序来处理对象间的共 同特性,再编写几个专用子程序去处理它们间的不同特性就可以了。有些操作,例如 Getsize(),

可能在任何抽象层次上都适用。程序语言支持 Getsize()这种直到运行时才需要知道操作对象的 子程序特性称为“多形性”。像 C++等面向对象的语言,自动支持继承性和多形性。而以对象为 基础的语言,如 Ada 和过程性语言如 C 和 Pascal 则不支持这种特性。

对象与类

在面向对象设计中,最后一个关键概念是对象与类。对象是程序在运行时其中的任何一个 实体,而类则是当你看程序清单时存在的一个静态实体。对象是在程序运行时具有特定值和属 性的动态实体。例如,你可以定义一个具有名字、年龄、性别等属性的人,而在运行时则会遇 到 Nancy,Tom 等人,也就是说,对象是类的特例,如果你对数据库术语很熟悉的话,它们的 区别与其中“模式”与“实例”的区别是类似的,在本节其余部分将不严格区分这些词,常会 把两种实体都称为“对象”。

7.3.2 面向对象设计的步骤 面向对象设计的步骤是:

・ 识别对象及其属性,它往往是数据。

・ 确定对每个对象可以做些什么。

・ 确定每一个对象可以对其它对象做些什么。

・ 确定每个对象对其它对象来说是可见的部分——哪一部分是开放的,哪一部分是专用 的。

・ 确定每个对象的公共接口。

这些步骤下一定非要按某一特定顺序来进行,但是却需要重复。逐次迭代逼近对面向对象 设计是与其它设计方法同样重要的,下面将分别论述这些步骤。

识别对象及其属性。计算机程序通常是以客观世界实体为基础的,例如,你可以用客观世 界中的雇员,时间卡及帐单为基础来建造一个时间——记帐系统。图 7-3 中表示了从面向对象 观点来看,这一系统的表现形式。

在图形系统中的对象将包括:窗口、对话框、按钮、字体、绘图工具等。对问题域进行进 一步研究,可能会发现比这种一对一方式更好的软件对象识别方法,但是,从客观世界中的真 实对象出发总是一个比较好的方法。

识别对象属性并不比识别对象困难。每一个对象都有与计算机程序相关联的特性。例如,

在时间——记账系统中,雇员对象将具有姓名、标题和记账率;顾客对象将有姓名、支票地址、

收支状况及存款余额等;账单对象具有欠账数量、顾客姓名、日期等等。

图中对象的图形符号与第六章讲述的模块符号类似。

确定可以对一个对象做些什么。对每一个对象都可以进行一系列操作,在时间——记账系 统中,雇员的记账率等可以变动,可以要求提供雇员的奖励情况等,顾客对象可以更改其存款 额或地址等。

确定对象之间可以互相做些什么。这一步骤与其字面意义是相似的。在时间——记账系统 中,雇员可以对其它对象做些什么呢?做不了什么。雇员所能做的一切便是输入时间卡信息。

而账单则可以接受时间卡信息,在更复杂的系统中,其它相互作用更为明显。

确定每一个对象中对其它对象来说是可见的部分。在设计中的一个关键问题就是决定对象 的哪些部分应该是可见的,哪些部分应该是隐蔽的。对于数据和功能来说,都要做出这种确定。

在表示时间——记账系统的图 7-3 中只表示出了可见的部分,隐蔽的部分则被藏在黑盒子

图 7-3 四个主要对象组成的记帐系统

中。顾客与雇员对象看起来是非常复杂的,因为它们每一个都具有七八个可见的特性。这种复 杂的表现形式是图示法的一个弱点,这种情况会随着可见特性的增加而恶化。而一个精心设计 好的对象往往有许多附加的可见特性。

中。顾客与雇员对象看起来是非常复杂的,因为它们每一个都具有七八个可见的特性。这种复 杂的表现形式是图示法的一个弱点,这种情况会随着可见特性的增加而恶化。而一个精心设计 好的对象往往有许多附加的可见特性。

在文檔中 Code Complete 代码大全 (頁 110-114)