第2 繼承

前面已經(jīng)說過了,繼承至少有2個(gè)語義: 實(shí)現(xiàn)繼承和類型繼承,在說明這兩個(gè)東西之前,我們繼續(xù)來看上面的例子

Person>>playSoloOnInstrument:instrument
  instrument playNote: Note C;
             playNote: Note D;
             playNote: Note E.

Person
>>playBackgroundOnInstrument:instrument
  instrument playChord: Chord C1;
      playChord: Chord C1;
             playChord: Chord C1;

Person
>>playBWV996OnInstrument:instrument
   instrument playNote: Note C;
              playChord: Chord C;
              playNote: Note D.

現(xiàn)在我們看playBWV996這個(gè)消息,BWV996是Bach所寫一個(gè)魯特琴組曲,魯特琴是彈撥樂器,同時(shí)也是和聲樂器(所謂和聲樂器就是可以演奏和聲)。在很多樂器上都有改編的版本,比如魯特琴的近親吉他等等,這個(gè)時(shí)候,我們可以實(shí)現(xiàn)這樣幾個(gè)類

Lute>>playNote:note
  
Lute
>>playChord:note
  

Guitar
>>playNote:note
  
Guitar
>>playChord:note
  

Bass
>>playNote:note
  

然后我們可以嘗試以此調(diào)用

vincent.playBWV996OnInstrument: Guitar new.
vincent.playBWV996OnInstrument: Lute 
new.
vincent.playBWV996OnInstrument: Bass 
new.

最后一個(gè)會(huì)得到一個(gè)messageNotUnderstand的錯(cuò)誤。也就是說,對(duì)于Bass而言由于不能演奏和聲從而不能演奏BMV996(不過這個(gè)世界上能人太多了...哎),我們換到靜態(tài)類型面向?qū)ο笙到y(tǒng)來看。
對(duì)于第一個(gè)方法,playSolo的時(shí)候我們要求的類型是能夠演奏單音的。我們可以寫出來

1interface SoloInstrument {
2  SoloInstrument playNote(Note note);   
3}

對(duì)于第二個(gè)方法,playChord的時(shí)候我們要求的類型是能夠演奏和弦的,我們可以寫出來

1interface ChordInstrument {
2  ChordInstrument playChord(Chord note);   
3}

而對(duì)于第三個(gè)方法,playBWV996的時(shí)候我們要求既能演奏和弦也能演奏單音,這個(gè)時(shí)候出現(xiàn)一個(gè)問題,我們?cè)趺刺幚鞩nstrument的繼承關(guān)系?一個(gè)能演奏和弦的樂器是否可以演奏單音(答案是一般而言是的,但是也不排除有一些不是這樣的)?還是我們簡單的寫:

1interface SoloAndChordInstrument extends SoloInstrument, ChordInstrument{
2}

或者

1interface BWV996Playable {
2
3  BWV996Playable playNote(Note note); 
4  BWV996Playable playChord(Chord note);  
5}

對(duì)于動(dòng)態(tài)類型簡單的隱性類型約定,顯示的類型系統(tǒng)帶來的一個(gè)副作用就是我們必須處理類型之間的關(guān)系。注意這里是類型之間的關(guān)系,而不是對(duì)象之間的關(guān)系。老莊同志批了很多篇的面向?qū)ο蟮某橄螅嫦驅(qū)ο蟮念愋拖到y(tǒng)以及面向?qū)ο蟮谋倔w論,其實(shí)都在是在類型關(guān)系上折騰,而不是在對(duì)象關(guān)系上折騰。而事實(shí)上面向?qū)ο蟮?STRONG>類型系統(tǒng)并非必然就是靜態(tài)類型系統(tǒng),而我們的類之間的關(guān)系不一定就和類型的關(guān)系相一致。就像上例所示,在Smalltalk里,Lute,Guitar和Bass之間沒有任何的繼承關(guān)系,但是對(duì)于person的3個(gè)消息而言,它們卻是有類型的。

因此老莊所批的,是對(duì)象類型系統(tǒng)的抽象能力,而非面向?qū)ο蟮某橄竽芰ΑU缢陬愋拖到y(tǒng)里所給的例子,那張他認(rèn)為很失敗的面向?qū)ο蟮膱D,其實(shí)可以完全不依賴?yán)^承來實(shí)現(xiàn),而對(duì)這個(gè)類型系統(tǒng)的消費(fèi)者而言,他們能夠以一定的類型的觀點(diǎn),來處理這個(gè)系統(tǒng)的對(duì)象。

而老莊最后一個(gè)結(jié)論:

我的結(jié)論是:“一個(gè)類型,是由其本質(zhì)決定了所能表現(xiàn)出的可操作性,而不是有其所能接受的操作決定了其本質(zhì)。然而,OO正好把這個(gè)問題搞反了!”

我的看法是,這句話根本就是詭辯,前面半句的主語是“一個(gè)類型”,后面半句的主語是"OO"...

雖然前半句是對(duì)的,但是換一樣說法可能更好:"所能接受的操作反映了其本質(zhì)",面向?qū)ο蟊旧砭蜎]有說我要做一個(gè)本質(zhì)抽象,這一點(diǎn)在Smalltalk的類型判斷操作上的可能是一個(gè)佐證,Smalltalk用isKindOf來判斷繼承關(guān)系,我們來玩一個(gè)文字游戲,改成俚語就是kinda,也就是"有一點(diǎn),有幾分"的意思,而不是說,“就是”,或者“從分類學(xué)上可證明之類的含義”。我再舉一個(gè)齷齪的例子。

vincent ballon: AirBallon new.
vincent ballon: Condom 
new.

氣球和保險(xiǎn)套,對(duì)于ballon這個(gè)方法而言是一個(gè)類型,都是"有幾分"可以吹起來。但是我怎么定義一個(gè)精確的本質(zhì)?Ballonable?還是MakeFromLatexAndVeryThin?或者簡單說FlexableAndThin?

在繼承這一點(diǎn)上,我想老莊引文中:Elminster的話是從事物的特征與屬性歸納出它的“類型”。恰恰對(duì)于靜態(tài)類型面向?qū)ο笙到y(tǒng)是可行的。如我前文所述,我把一個(gè)object和所有sender的約定(也就是interface),繼承在一起,恰恰就是一個(gè)頗為恰當(dāng)?shù)念愋投x。

而對(duì)于動(dòng)態(tài)類型系統(tǒng)里的面向?qū)ο笳Z言,繼承的也有類型繼承的含義,但是并不是唯一的途徑。用一句我們常說的話,在靜態(tài)類型系統(tǒng)里,類型和類是緊耦合的,動(dòng)態(tài)類型系統(tǒng)中他們的耦合比較松。

從此而觀,所有對(duì)于面向?qū)ο蟮恼軐W(xué)考慮以及本體的思考,對(duì)于動(dòng)態(tài)面向?qū)ο笙到y(tǒng)已經(jīng)不是那么迫切了。而把對(duì)象類型系統(tǒng)的不足歸咎于面向?qū)ο蟮牟蛔悖菜坪跽摀?jù)不足。