第1 關(guān)于"接口"
關(guān)于接口的問題老莊說對了,這個東西并不屬于面向?qū)ο蟮母拍睿以趧討B(tài)類型面向?qū)ο笳Z言(比如Ruby, Smalltalk里),根本沒有這個東西。這是一個純粹的靜態(tài)類型面向?qū)ο笳Z言的特性,或者直接說,接口就是一個純類型(Type)。還是上次的例子:
在我接觸Smalltalk的最開始的一段時間里,這種地方是讓我最難受,我已經(jīng)習(xí)慣了用類型輔助我的思維,但是我發(fā)現(xiàn)我在Smalltalk里做不到,雖然我可以寫出
但是他卻不是一個接口,我可以很用
來構(gòu)造一個Instrument之后在它之上調(diào)用playNote方法,然而我會得到一個messageNotUnderstand的錯誤,Smalltalk和Ruby里沒有Abstract的概念。也就是說abstract method,abstract class以及interface,都不是面向?qū)ο蟮母拍睿ɑ蛘邍栏褚恍┱f,都不是面向?qū)ο蟮谋仨毜母拍睿敲嫦驅(qū)ο箢愋拖到y(tǒng)的概念。那么在Smalltalk里我們會怎么做呢?
對于playSoloOnInstrument:instrument,我們對于instrument的類型是有要求的,就是它必須能夠接受playNote這個消息。當(dāng)然這個類型需要是隱性,我也可以對等的寫出靜態(tài)面向?qū)ο蟮拇a把這個隱性的類型顯示的表示出來:
同樣對于第二個方法我們也可以寫出來:
如果我們需要多于一個的消息也是一樣的,比如
同樣這個時候隱性的類型需要就是
那么接口是什么呢?我給出一個不確切的說法,interface是一個消息的發(fā)送者(sender)和一個消息的接受者(reciver)間的一種類型的約定,也就是說在我看來interface的用處主要在細粒度的顯式類型約定。我有一個同事,每次寫代碼都為一個Test Case所要測試的對象定義一個interface,每個interface都只有2-3個方法(lx同學(xué)夸你呢:D),這是很得interface之三味的用法。這種的做法對于在靜態(tài)的面向?qū)ο笙到y(tǒng)的好處我們在繼承里再論述。
至于老莊所說的接口是多繼承的一種代替品,這只不過是世俗的看法,在靜態(tài)類型的面向?qū)ο罄铮^承至少有2個語義:
1.實現(xiàn)繼承,這個在Smalltalk,Ruby,C++里有,而在java里沒有,C++里是通過private extends來實現(xiàn)的
這也是C++里為數(shù)不多的subclass不是subtype的例子。
2.類型繼承,這個在C++和java里有,而在smalltalk,ruby有卻不明顯。
類型繼承的極致就是C++里的純虛父類
也就是java里的interface
因此,也就明了了,所謂“面向接口編程”是以類型作為約定的編程。我覺得這點大家一定不陌生,面向接口的編程里interface都很小而且約定明確。但是要說明一點的是,這個東西和"面向抽象而不要面向具體編程"其實還不一樣,所以這個東西也就僅僅能算是靜態(tài)類型面向?qū)ο蟮囊粋€慣用法,還到不了原則這么高。