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