第2 繼承
前面已經說過了,繼承至少有2個語義: 實現繼承和類型繼承,在說明這兩個東西之前,我們繼續來看上面的例子
現在我們看playBWV996這個消息,BWV996是Bach所寫一個魯特琴組曲,魯特琴是彈撥樂器,同時也是和聲樂器(所謂和聲樂器就是可以演奏和聲)。在很多樂器上都有改編的版本,比如魯特琴的近親吉他等等,這個時候,我們可以實現這樣幾個類
然后我們可以嘗試以此調用
最后一個會得到一個messageNotUnderstand的錯誤。也就是說,對于Bass而言由于不能演奏和聲從而不能演奏BMV996(不過這個世界上能人太多了...哎),我們換到靜態類型面向對象系統來看。對于第一個方法,playSolo的時候我們要求的類型是能夠演奏單音的。我們可以寫出來
對于第二個方法,playChord的時候我們要求的類型是能夠演奏和弦的,我們可以寫出來
而對于第三個方法,playBWV996的時候我們要求既能演奏和弦也能演奏單音,這個時候出現一個問題,我們怎么處理Instrument的繼承關系?一個能演奏和弦的樂器是否可以演奏單音(答案是一般而言是的,但是也不排除有一些不是這樣的)?還是我們簡單的寫:
或者
對于動態類型簡單的隱性類型約定,顯示的類型系統帶來的一個副作用就是我們必須處理類型之間的關系。注意這里是類型之間的關系,而不是對象之間的關系。老莊同志批了很多篇的面向對象的抽象,面向對象的類型系統以及面向對象的本體論,其實都在是在類型關系上折騰,而不是在對象關系上折騰。而事實上面向對象的類型系統并非必然就是靜態類型系統,而我們的類之間的關系不一定就和類型的關系相一致。就像上例所示,在Smalltalk里,Lute,Guitar和Bass之間沒有任何的繼承關系,但是對于person的3個消息而言,它們卻是有類型的。因此老莊所批的,是對象類型系統的抽象能力,而非面向對象的抽象能力。正如他在類型系統里所給的例子,那張他認為很失敗的面向對象的圖,其實可以完全不依賴繼承來實現,而對這個類型系統的消費者而言,他們能夠以一定的類型的觀點,來處理這個系統的對象。
而老莊最后一個結論:
我的看法是,這句話根本就是詭辯,前面半句的主語是“一個類型”,后面半句的主語是"OO"...雖然前半句是對的,但是換一樣說法可能更好:"所能接受的操作反映了其本質",面向對象本身就沒有說我要做一個本質抽象,這一點在Smalltalk的類型判斷操作上的可能是一個佐證,Smalltalk用isKindOf來判斷繼承關系,我們來玩一個文字游戲,改成俚語就是kinda,也就是"有一點,有幾分"的意思,而不是說,“就是”,或者“從分類學上可證明之類的含義”。我再舉一個齷齪的例子。
氣球和保險套,對于ballon這個方法而言是一個類型,都是"有幾分"可以吹起來。但是我怎么定義一個精確的本質?Ballonable?還是MakeFromLatexAndVeryThin?或者簡單說FlexableAndThin?
在繼承這一點上,我想老莊引文中:Elminster的話是從事物的特征與屬性歸納出它的“類型”。恰恰對于靜態類型面向對象系統是可行的。如我前文所述,我把一個object和所有sender的約定(也就是interface),繼承在一起,恰恰就是一個頗為恰當的類型定義。而對于動態類型系統里的面向對象語言,繼承的也有類型繼承的含義,但是并不是唯一的途徑。用一句我們常說的話,在靜態類型系統里,類型和類是緊耦合的,動態類型系統中他們的耦合比較松。從此而觀,所有對于面向對象的哲學考慮以及本體的思考,對于動態面向對象系統已經不是那么迫切了。而把對象類型系統的不足歸咎于面向對象的不足,也似乎論據不足。