冒号课堂§2.3:对象范式
冒号课堂
第二课 重要范式(3)
2.3对象范式——民主制社会的编程法则
民为贵,社稷次之,君为轻 ——《孟子·尽心下》
关键词:编程范式,OOP,面向对象编程,过程式编程,重用性,易用性
摘要:对象式编程简谈
!预览
· 如果把整个流程看作一颗倒长的大树,过程式编程自树根向下,逐渐分支,直到每片树叶,类似数学证明中的分析法,即执果索因的逆推法;OOP则从每片树叶开始,逐渐合并,直到树根,类似数学证明中的综合法,即执因索果的正推法
· 与其说OOP更具重用性,不如说更具易用性
· 函数是被动的实体,对象是主动的实体
· 过程式程序的世界是君主制的;OO程序的世界是民主制的
· 封装使得公民拥有个体身份,继承使得公民拥有家庭身份,多态使得公民拥有社会身份
?提问
- OOP是一种特殊的命令式吗?
- OOP的基本思想是什么?
- OOP到底好在哪里?
- OOP将要一统天下吗?
- 过程式编程与OOP在设计理念上有什么差异?
:讲解
短憩之后,引号迫不及待地问:“面向对象的范式应该是一种特殊的命令式吧?”
“面向对象?”冒号咕哝着,“姑且称之为OO或对象式吧,既不标新立异,也不以讹传讹。在回答你的问题之前,请先回答我的:什么是OOP?”
引号应答如流:“OOP(Object-Oriented programming)是一种计算机编程模式,它以对象作为问题空间的基本元素,利用对象和对象间的相互作用来设计程序。所谓对象,是实际问题中实体的抽象,具有一定的属性和功能。OOP的三个基本特征是:封装性、继承性和多态性。所谓封装性就是——”
冒号作了个暂停的手势:“OOP的的基本特征相信大家早就耳熟能详了,那么根据你刚才的定义,能否得出OOP一定是命令式的结论?”
引号歪头想了一阵,答道:“从定义上好像并不能得出,难道C++、Java、C#不是命令式的吗?”
冒号回答:“当然是,但这不妨碍Clos成为OO版的Lisp,而Prolog也有不少融入OO特征的扩充,如Visual Prolog、Logtalk等。OOP虽然是在命令式的基础上发展起来的,但其核心思想可泛化为:以数据为中心组织逻辑,将系统视为相互作用的对象集合,并利用继承与多态来增强可维护性和可重用性。这种思想也能应用到函数式和逻辑式中,只不过对象的方法从命令式中的过程分别换成函数式中的函数和逻辑式中的断言罢了。大致说来,命令式、函数式和逻辑式互相平行,而OOP与它们正交。”
问号提问:“OOP已经成为一种潮流,上堂课列举的十二种流行语言中只有C不是OO的,这是否意味着OOP将要一统天下?”
“严格说来,VB(VB.NET除外)和JavaScript也不是OO的,只是基于对象的(Object Based)[1]。” 冒号纠正道,“至于OOP是否会一统天下,答案是否定的。首先,与能独当一面的三类最基本的范式不同,纯粹的OOP是不存在的[2],必须结合其他范式;其次,世上没有包治百病的万灵丹方,OOP也不例外。用软件业的行话来说:没有银弹(No silver bullet)[3]。OOP最适用于大型复杂的、交互式的、尤其是与现实世界密切相关的系统,但在小型应用、数学计算、符号处理等方面并无优势。需要指出的是,语言和范式的流行,与大公司支持和商业推动是密切相关的。有人说OOP其实是MOP(Money-Oriented Programming),即以金钱为导向的。虽有过激之嫌,但有经验的股民都知道,有主力运作的股票总是涨得快一些的。当然OOP能流行,自有独到之处,谁能说说它到底好在哪里?”
逗号抢答:“OOP能提高软件的可维护性和可重用性。”
冒号反问:“为什么过程式编程的可维护性和可重用性就差呢?”
感到来者不善,逗号有点发虚:“因为OOP具有信息隐藏、继承和多态的特征。”
冒号并不买帐:“首先,将可维护性和可重用性与OOP划等号,是只见树木,不见森林——那是所有范式和语言的共同目标。其次,以C语言为例,信息隐藏可用关键字static来实现;继承可用合成( composition)来代替;多态虽然困难些,也有变通之法。更何况这些只是手段而非目的,只要设计合理,C程序同样具有可维护性和可重用性,性能效率还更优越。即使在OOP日益风行的今天,C的占有率始终稳踞前列,许多大型复杂软件如操作系统、数据库等仍以C为主,这足以证明其仍堪大用。”
见逗号有些理屈词穷,冒号语气放缓:“请不要误解,我并非OOP的反对者,相反今后还要重点讨论它。但我希望大家少一点照本宣科和人云亦云,多一点独立思考,甚至不妨标新立异。 ”
稍作停顿,冒号继续发问:“过程式编程与OOP在设计理念上有什么区别?”
“过程式编程的理念是以过程为中心,自顶向下、逐步求精[4]。”引号一出口就自感有些“照本宣科”,见冒号正用鼓励的目光看着他,这才继续说下去,“OOP则正相反,以数据为中心,自底向上、逐步合并。”
冒号首肯道:“如果把整个流程看作一颗倒长的大树,过程式编程自树根向下,逐渐分支,直到每片树叶,类似数学证明中的分析法,即执果索因的逆推法;OOP则从每片树叶开始,逐渐合并,直到树根,类似数学证明中的综合法,即执因索果的正推法。 ”
句号心领神会:“倘若把树根看成主函数,离树根越近,离用户需求也越近。如果用过程式编程,由于是逆推法,树干改变容易导致树枝相应改变,因此一旦用户需求发生变化,可能会从树根波及到树枝甚至树叶,维护起来殊为不易。相反OOP从树叶开始设计,离用户需求较远,抽象程度较高,受波及的程度较小,因此更易维护和重用。”
冒号拊掌赞道:“好极了!”
问号不解:“您刚才不还说C程序同样具有可重用性吗?”
冒号微微一笑:“数学中分析法与综合法往往是结合起来使用的,过程式编程与OOP也是如此,只不过各有偏重罢了。句号的一番话虽不无道理,但也授OOP的反对者以口实:OOP鼓吹的可重用性来自‘自底向上’的设计模式,而这种模式并非OOP的专利。其实软件设计的最重要的并不是编程语言,甚至也不是编程范式,而是抽象思维。关于这一点,我们今后还会详细阐述。”
叹号不甘寂寞,插言道:“OOP以对象为基本模块单位,而对象是现实中具体事物和抽象概念的模拟,这使得编程设计更自然更人性化。”
“深合吾意!”冒号挥动着右手,“尽管OOP最大的卖点是其高度的可重用性,相比其他范式却并不具明显优势。但它更接近人类的认知模式,编程者更容易也更乐于用这种方式编程,这是它深入人心的一个重要原因。比较一下两种用法:牛.吃(草)与吃(牛,草),哪种更接近人类思维?”
有人在底下嘀咕:“如果把牛换成狗,那么一个是狗吃屎,一个是吃狗屎。”
全班捧腹。
冒号也忍不住笑了:“OOP人性化的另一表现是其接口简洁易记。看看Win32 API、Unix API等之类操作系统接口或OCI之类的数据库接口,函数的参数动辄七八个乃至上十个,函数名和数据结构成员也多冗长晦涩,既难记又易错。相比之下,相应的Java的API显然平易近人得多。”
问号刨根问底:“为什么C的API不能象Java的那么简洁呢?”
冒号释疑:“单纯这么比较其实对C并不公平,因为Java的API虽然简洁易用,但功能上与相应C的API并不等同,换句话说,Java把接口粗粒度化了。”
“接口粗粒度化?”引号质疑道,“就是把一些函数包装起来吧?我们也可以用C将操作系统、数据库之类的API再包装一下。”
“事实上许多软件公司都曾这样做过。”冒号颔首作答,“但C函数不像Java对象,本身没有状态,只有依靠参数传递或外部变量来维持相关函数之间的联系,包装后的接口肯定不如Java简洁,但应该比Java高效。说白了,OOP就是将相关的函数用数据粘合,重新包装后再贴上对象的标签。从这种角度上看,与其说OOP更具重用性,不如说更具易用性。”
叹号狐疑道:“OOP并不更具重用性?这可是它的金字招牌啊!”
冒号冷哼一声:“不要被金字招牌晃晕了眼,我来问你:是收音机、电视机之类的电器产品更具重用性呢,还是电阻、电容之类的电器元件更具重用性?”
“当然是电器元件啦。”叹号冲口而出。
冒号因势利导:“每个电器元件具备单一的功能,正如过程式中的函数;每个电器产品是对多个相互关联的电器元件的封装,正如OOP中的对象。同样的电器元件可用于不同的电器产品,具有高度的可重用性,而电器产品重用性低,但易用性高。[5] ”
众人犹自将信将疑。
“对一个没有独立思考习惯的人来讲,与其说他认同一个理论,倒不如说他认同该理论倡导者的权威。而在他仰视权威的同时,也把自己的思想交托给了权威。”冒号颇具犬儒之风,“你们可以怀疑我的观点,但绝不可放弃自己的思考。请注意,这就是我在第一堂课提到的精神——批判精神。”
冒号这时停了下来,与在座的每位逐一对视。他仿佛想通过目光把这种精神注入到每个人的身上,就像武侠小说中通过手掌将内功传输给他人一样。并不是每个人都能理解冒号的用心,但都或多或少地感受到一种异样的气氛。
“关于OOP今天就谈到这里。”冒号恢复了常态,“请不要奇怪为何如此流行的编程范式我却一带而过,那是因为你们对它相对比较熟悉,而我们这一轮只是在作热身运动,以后再作专项训练。在结束之前,我们引进一个新视点:过程式编程的模块以函数为单位,OOP的模块以对象为单位,二者的区别是:函数是被动的实体,对象是主动的实体。过程式程序的世界是君主制的,主函数是国王,其他函数是臣民,等级分明,所有臣民在听命于上级的同时也对下级发号施令,最终为国王服务;OO程序的世界是民主制的,所有对象都是独立而平等的公民,有权利保护自己的财产和隐私并向他人寻求服务,同时有义务为他人提供承诺的服务,公民之间通过信息交流来协作完成各种任务。更进一步地,封装使得公民拥有个体身份,需要对自己负责;继承使得公民拥有家庭身份,需要对家庭负责;多态使得公民拥有社会身份,需要对社会负责。欲知个中玄机,且听我日后慢慢道来。”
众人顿觉耳目为之一新。
,插语
[1] 所谓基于对象的,有两种不同的涵义。一种指“限制版”的OOP,即具备对象概念,但不具备OOP的一些其他特征,如继承或多态等。Visual Basic(不包括Visual Basic .NET)正属于此类。另一种指基于原型的(prototype-based),或者说基于实例的(instance-based),而不像通常OOP是基于类的(class-based)。JavaScript、NewtonScript、MOO等语言即属此类。
[2] 这里所谓“纯粹的OOP”并非指一般意义上的“pure OOP”(即所谓的“一切都是对象”),而指单纯的、不含其他范式的OOP。
[3] 出自Fred Brooks的著名文章《no silver bullet》(参见文献【2】)。他认为没有一项技术或管理方法的发展能保证,在十年内让软件的生产力、可靠性或简洁性等方面提高一个数量级。常用来泛指没有一项软件技术或方法是万能的。
[4] 更准确地说,这是前文提到的结构化编程思想。
[5] 当然,也可把电器元件看作对象,只不过颗粒度比电器产品更小而已。但函数的颗粒度的确普遍比对象的小,故文中论点依然成立。
。总结
· OOP大多是命令式的,但也有函数式的和逻辑式的OO语言。
· OOP的核心思想可以归纳为:以数据为中心组织逻辑,将系统视为相互作用的对象集合,并利用继承与多态来增强可维护性和可重用性。
· OOP既不能脱离其他范式,也绝非适用于一切应用。
· 可维护性和可重用性是所有范式和语言的共同目标,并非OOP所独有。
· 与其说OOP更具重用性,不如说更具易用性。
· 过程式编程以过程为中心,自顶向下,逐步求精。
· 对象式编程以数据为中心,自底向上,逐步合并。
· 过程式程序的世界是君主制的,OO程序的世界是民主制的。
· 封装使得对象拥有个体身份,继承使得对象拥有家庭身份,多态使得对象拥有社会身份。
“”参考
[1] Wikipedia.Object-oriented programming.http://en.wikipedia.org/wiki/Object-oriented_programming
[2] Frederick Brooks.The Mythical Man-month.Boston:AddisonWesley,1995.179-203