第1 關(guān)于"接口"

關(guān)于接口的問題老莊說對了,這個東西并不屬于面向?qū)ο蟮母拍睿以趧討B(tài)類型面向?qū)ο笳Z言(比如Ruby, Smalltalk里),根本沒有這個東西。這是一個純粹的靜態(tài)類型面向?qū)ο笳Z言的特性,或者直接說,接口就是一個純類型(Type)。還是上次的例子:

 1interface Instrument {
 2   void playNote(Note note);
 3   void playChord(Chord chord);
 4}

 5
 6in Person Class
 7
 8void playSolo(Instrument instrument) {
 9 
10}

在我接觸Smalltalk的最開始的一段時間里,這種地方是讓我最難受,我已經(jīng)習(xí)慣了用類型輔助我的思維,但是我發(fā)現(xiàn)我在Smalltalk里做不到,雖然我可以寫出

Instrument>>playNote:note
  
^self subclassResponsibility.

Instrument
>>playChord:chord
  
^self subclassResponsibility.

但是他卻不是一個接口,我可以很用

instrument = Instrument new.
instrument playNote: Note C.

來構(gòu)造一個Instrument之后在它之上調(diào)用playNote方法,然而我會得到一個messageNotUnderstand的錯誤,Smalltalk和Ruby里沒有Abstract的概念。也就是說abstract method,abstract class以及interface,都不是面向?qū)ο蟮母拍睿ɑ蛘邍栏褚恍┱f,都不是面向?qū)ο蟮谋仨毜母拍睿敲嫦驅(qū)ο箢愋拖到y(tǒng)的概念。那么在Smalltalk里我們會怎么做呢?

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;

對于playSoloOnInstrument:instrument,我們對于instrument的類型是有要求的,就是它必須能夠接受playNote這個消息。當(dāng)然這個類型需要是隱性,我也可以對等的寫出靜態(tài)面向?qū)ο蟮拇a把這個隱性的類型顯示的表示出來:

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

同樣對于第二個方法我們也可以寫出來:

1interface Instrument {
2   Instrument playChord(Note note);  
3}

如果我們需要多于一個的消息也是一樣的,比如

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

同樣這個時候隱性的類型需要就是

1interface Instrument {
2   Instrument playNote(Note note);  
3   Instrument playChord(Note note);  
4}

那么接口是什么呢?我給出一個不確切的說法,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)的

1class SubClassA: private ImplementationParent {
2}

這也是C++里為數(shù)不多的subclass不是subtype的例子。

2.類型繼承,這個在C++和java里有,而在smalltalk,ruby有卻不明顯。

類型繼承的極致就是C++里的純虛父類

1abstract class Parent {
2
3  public asbtract void method1() = 0;
4  public asbtract void method2() = 0;
5}

也就是java里的interface

1interface Parent {
2   void method1();
3   void method2();
4}

因此,也就明了了,所謂“面向接口編程”是以類型作為約定的編程。我覺得這點大家一定不陌生,面向接口的編程里interface都很小而且約定明確。但是要說明一點的是,這個東西和"面向抽象而不要面向具體編程"其實還不一樣,所以這個東西也就僅僅能算是靜態(tài)類型面向?qū)ο蟮囊粋€慣用法,還到不了原則這么高。