开篇之前先说明一下,我和老庄有着不错的私交,他最初写丧钟系列的时候,我是忠实的拥趸之一,庄兄见我尚有寸尺所长,还在丧钟系列里引用了我的几个观点。然而最近一段时间里,我作了这样几件事情:
经过种种之后,发现当初所谓鸣OO之丧钟,实在是言过其实。--------------------------------------------------------------------------------------------------------------------------------------------------------------第0 关于"面向对象"
既然要为人家敲丧钟,先要找对了苦主,不然岂不是白忙活了一场。什么是面向对象?这个问题太大,我们举一个很常见的例子:
这个例子自然很不充分,不过继承啊,接口啊,多态啊,略举大概,尚可以作为一个讨论的例子。从这个例子里,我们发现有这样一个事实,就是Person类有两个方法
分别表示,需要一个类型为Instrument的对象instrument,然后对他进行相应的操作,而且,从概念上来讲,第一个方法,使演奏旋律的,也就是单音,而第二个方法是演奏和声的。那么,如果我有一个类
我们知道,玻璃瓶装了水也是可以发出声音,Mozart可是为玻璃瓶写过曲子的,而这里我们却不能
因为我们在构造Person类的时候,我们的play方法是依赖一个类型为Instrument的Object,换而言之,我们这里所谓的Object-Oriented其实称作Object-with-Type-Oriented的更合适,其实这类语言有一个专有名词,叫做static type object oriented。那Object-Oriented是不是就一定是Static Type Object Oriented的呢?不然,比如在Ruby里,我们可以写成:
然后就可以
同样也可以
在这里,类型可以推演也可以留到runtime检查,如果是推演的话,在playNote里,由于thing调用了playNote方法,所以传进来的对象必须要刻意接受playNote这个消息,于是Guitar和GlassBottle都是可以通过,因此我即可以演奏我的Perez 711,也可以敲玻璃瓶。这种方式叫做dynamic type。
那么static type和dynamic type区别在那呢?static type认为,class就是type,type就是class; subclass就是subtyping,subtyping就是subclass(其实这句不严谨,在c++里可以使得subclass不是subtyping,但是java里就没办法了);而dynamic type则认为类型和class没有关系,类型取决于一个对象能够接受的消息。
那么哪个才是面向对象之真貌呢?遗憾的说,static type并不是最初的面向对象。以对象作为模块化的单位,始自Simula 67。但是Simula 67并不是一个面向对象系统,以目前的观点来看,充其量是Object-based,第一个面向对象语言当推Smalltalk,Smalltalk是dynamic type的。不过Smalltalk不太流行,第一个大面积流行的面向对象语言是C++,C++是static type的,正如Lisp是第一个函数式编程语言,很多Lisp的特性被当作函数式语言的共有特性(比如表是最重要的数据结构,轻语法)一样,所以很多人以为面向对象就必然是static type(比如老庄和我)。对于面向对象的误解,80%来自C++。也就是说,80%来自于static type的面向对象系统。将static type面向对象归咎于整个面向对象,我辈实在是大而无当言过其实。
后面我再一一将老庄所言之OO不当之处加以说明