谈到面向对象,这方面的文章非常多。但是,明确地给出对象的定义或说明对象的定义的非常少——至少我现在还没有发现。其初,“面向对象”是专指在程序设计中采用封装、继承、抽象等设计方法。可是,这个定义显然不能再适合现在情况。面向对象的思想已经涉及到软件开发的各个方面。如,面向对象的分析(OOA,Object Oriented Analysis),面向对象的设计(OOD,Object Oriented Design)、以及我们经常说的面向对象的编程实现(OOP,Object Oriented Programming)。许多有关面向对象的文章都只是讲述在面向对象的开发中所需要注意的问题或所采用的比较好的设计方法。看这些文章只有真正懂得什么是对象,什么是面向对象,才能最大程度地对自己有所裨益。这一点,恐怕对初学者甚至是从事相关工作多年的人员也会对它们的概念模糊不清。下面我从一般的概念出发,再引申到软件开发领域中所涉及到的对象的概念。
上一篇文章中我曾举过一个树的例子来说明对象的概念。这里我仍然利用它对对象的概念做阐述。“对象”一词,英文为“Object”,德语为“Sachen”,都可以译做“物体”。其实所有的物体都可以作为我们的对象——只要我们注意并对它思考了。一个人从生下来到进行第一次的户外活动,他将接触到许许多多的新鲜事物,他将睁大眼睛好奇地看着这陌生的一切。也许对他来说,那些高大的东西,有干,有枝,有叶——虽然那时他并不知道这些——其映象已经深刻地印在了他的脑海中。此时对他来说,树并不是对象,因为在他的脑子当中只有树的映象,而没有对树的精神上的意向。当他再大一点时,也许他会想着爬到树上去玩一会儿——但此时树也还不是他的对象。存在的对象只是他自己——他想让自己去做某件事。长大以后,也许他他成了一名木匠——就像我们成了程序员,用他的锯子、斧头把一棵树砍下来做成一张桌子——就像我们利用Java 、C/C++语言开发出一套数据库系统。在这里,树是木匠的对象,而数据库系统是程序员的对象。于是,我在这里给对象下一个定义:对象是人脑中的物质意识和精神意识。通俗地讲,就是事物在人脑中的映象和人脑对事物的意向。之所以要在这里强调“事物”,是我要说明这里所说的“物质”并不是物理学中的物质,思维活动、事物间的关系我们也称为是物质的。
真正要在较深的层面上讨论什么是对象是很复杂的,因为这要涉及到精神意识本质的问题,远远超出了我们要讨论的范围。我们不要讨论什么高深的问题,就以实用为主。我就利用这个概念来举一个简单的例子。木匠前面有一张桌子。他可能要面临两个问题:一是给桌子添加一些部件如抽屉,这样桌子就可以放更多的东西;二是装饰一下桌子,使得它更美观。在这里,桌子是他的对象——他对桌子进行思考了,这使得他对桌子的意向性也明显地显露出来。我们甚至可以把改造桌子称为“面向对象的改造”,因为那不是随意的改造。这一点我在随后对面向对象思想的说明中提到为什么说是“不是随意的改造”。考虑一下“面向对象”,可以知道它是一个动宾关系的短语。动词“面向”表面,这个短语含有“如何去做”的意思,这可以说是涉及到了方法论的范畴了。这也给我们提供了一个重要的信息:“面向对象的做......”不仅牵涉到什么是对象的问题,还牵涉到如何去做的问题。木匠如何去做他的桌子,我们不必担心:他肯定能做好的——如果他是一个优秀的木匠的话。他有着丰富的经验,他有一套自己的方法,他知道如何去做。也许在做桌子之初就已经做了良好的设计以为以后的“升级”作准备。这就像一个经验丰富的程序员:他知道怎么设计才能让自己的程序结构清晰、易懂,容易排错也易于维护。
有一点要注意的是,对象不是实体,它可以脱离实体而存在。这是因为,对象只不过是人脑思维活动的产物;我们可以用某种方式如自然语言、图画等将它表示出来,就像我们在软件开发中所说的对象用类(程序当中)或系统结构图(如流程图,层次图,HIPO图等)来描述一样。
于是,我们就可以对象我们一般在软件开发领域里所讨论的对象下个定义了:对象由一个数据集以及对该数据集的操作组成。这个定义适合程序语言中的类,也适合对整个系统而言。也许大家会对这个定义觉得很熟悉:这不是程序或进程的定义吗?注意,这里的对象是有“自我意识”的,也就是说,它是有自己的行为的。而“进程”指的是一系列的二进制流的集合,是一次运行活动。在程序中,我们用类来描述对象,而对整个的系统,我们用系统图来描述。在这里,系统也是我们的对象。数据集就像事物在我们大脑中的映像,对数据集的操作就如同我们对事物的意向。如果我们仔细考察系统的各个部分,那么,它们也可以看作是对象。“面向对象的XX”就是要求我们如何合理地分配对象之间的层次结构,使得它清楚明了,在保持效率的同时还便于排错、维护。我们有一个专业名词来表示已经定型、得到大家认可的软件方法,那就我们常说的模式。各行各业都会有它自己的一般的方法模式,如建筑业有建筑模式,软件开发有其开发模式。我想,当初爱因斯坦之所以做出几个丑陋的凳子,就是因为他不懂得凳子的设计模式吧。这就如同好多编程初学者,稍微大一点的程序就会写出杂乱不堪的、除了自己谁也看不懂的代码,也许过了几天连自己都看不懂了。
在软件开发过程当中,系统(我们面对的终极对象)的分析、设计才是最重要的。而这两方面是紧密结合在一起的。这两步没有做好,下面的编码实现工作很难玩成,可以说是寸步难行。我曾经在一家软件公司(说是公司,其实加上老板才只有六、七个人)做过一段时间。那时老板叫我们用Java做一个数据库系统(图书馆管理系统),用来当招牌,以后也好对接项目有利。我以为他会先拿出一个设计图让我们看,不料他说现在就开始做。说实在的,那时我对这方面根本没有经验。我当时就对他说,你至少得把你设计的蓝图给我们看一看吧?他说没有,他也不知道如何做,以前没做过。还说我们边做边学习。我说那至少你应该先做一做系统分析吧。他说要是我有这能力还能在这里呆着?结果可想而知,我们在那里呆了几天,这里瞧一瞧,那里看一看,又在机子上写一写,什么也没做成。老板看见我们稍微有所松懈,就不断地催促快做快做。后来我受不了,就一个人跑了。也不知道他们做成了没有。可以说这是一个不成功的例子。就算是写成了,没有分析、设计的结果肯定也是很难维护的。这就象是请来的木匠,把一套家具打造得很不合理,看上去非常糟糕可能还很不实用。有谁会愿意用这样的家具?程序包设计得不好,有谁能用得好?无论谁用起来都会很吃力。如果说一个项目没有设计好,即使开发出来了,后来的维护工作别人怎么能接手?在我们中国软件领域有这样事情的例子很多。当然,产生这样情况的原因很多,中国的体制、公司的实力也是一大方面。但是如何去做,有是一个范围很宽的话题了。
上面聊得多了。对象是一个比较广泛的概念,在我们通常软件领域里也是这样。对象之间可以包含对象。对木匠来说,一套组合家具是一个对象,一件衣柜也是对象——全局和局部都要考虑。对他们来说,如何从整体到部分的设计出受人好评的家具,是需要丰富的经验和良好的设计方法的。对我们来说也是这样。除了要打下扎实的基本功,积累丰富的经验,还要注意学习我们的前辈们给我们留下的东西,以及同行们的好的方法。现在,有关面向对象的书籍、文章都很多,我们都应该去看看、去学习。
全文说了这许多,只谈了有关面向对象的概念。有几位朋友来信问到如何划分对象层次、结构对系统运行的重要性等,受篇幅所限,不能述及。还有可能有的朋友对对象的理解不是很合理,这里我谈一下我的观点。对象在系统运行时是有其生命期的。但是,在运行内对象自身的改变(如,动态地增加、缩减功能,数据集的变化等)不能看作是改变了对象。例如对于一个二叉树,初始化时只有根节点,当然我们可以看作是一个节点对象,但一般我们是将它看成一个整体的二叉数对象。当树生成之后,它还是那个对象,而不能把它看成是另外一个对象了。如果你那样理解的话,就把对象的各个运行时期分离开来了,这就与对象的概念有曲解了。