我想,對於各位使用物件導向程式設計語言的程式員來說,“介面”這個名詞一定不陌生,但是不知各位有沒有這樣的疑惑:介面有什麼用途?它和抽象類別有什麼區別?能不能用抽象類別代替介面呢?而且,作為程式員,一定經常聽到“面向介面編程”這個短語,那麼它是什麼意思?有什麼思想內涵?和物件導向編程是什麼關係?本文將一一解答這些疑問。
1.面向介面編程和物件導向編程是什麼關係
首先,面向介面編程和物件導向編程並不是平級的,它並不是比物件導向編程更先進的一種獨立的編程思想,而是附屬於物件導向思想體系,屬於其一部分。或者說,它是物件導向編程體系中的思想精髓之一。
2.介面的本質
介面,在表面上是由幾個沒有主體代碼的方法定義組成的集合體,有唯一的名稱,可以被類或其他介面所實現(或者也可以說繼承)。它在形式上可能是如下的樣子:
interface InterfaceName
{
void Method1();
void Method2(int para1);
void Method3(string para2,string para3);
}
那麼,介面的本質是什麼呢?或者說介面存在的意義是什麼。我認為可以從以下兩個視角考慮:
1)介面是一組規則的集合,它規定了實現本介面的類或介面必須擁有的一組規則。體現了自然界“如果你是……則必須能……”的理念。
例如,在自然界中,人都能吃飯,即“如果你是人,則必須能吃飯”。那麼類比到電腦程式中,就應該有一個IPerson(習慣上,介面名由“I”開頭)介面,並有一個方法叫Eat(),然後我們規定,每一個表示“人”的類,必須實現IPerson介面,這就類比了自然界“如果你是人,則必須能吃飯”這條規則。
從這裡,我想各位也能看到些許物件導向思想的東西。物件導向思想的核心之一,就是類比真實世界,把真實世界中的事物抽象成類,整個程式靠各個類的執行個體互相通訊、互相協作完成系統功能,這非常符合真實世界的健全狀態,也是物件導向思想的精髓。
2)介面是在一定粒度視圖上同類事物的抽象表示。注意這裡我強調了在一定粒度視圖上,因為“同類事物”這個概念是相對的,它因為粒度視圖不同而不同。
例如,在我的眼裡,我是一個人,和一頭豬有本質區別,我可以接受我和我同學是同類這個說法,但絕不能接受我和一頭豬是同類。但是,如果在一個動物學家眼裡,我和豬應該是同類,因為我們都是動物,他可以認為“人”和“豬”都實現了IAnimal這個介面,而他在研究動物行為時,不會把我和豬分開對待,而會從“動物”這個較大的粒度上研究,但他會認為我和一棵樹有本質區別。
現在換了一個遺傳學家,情況又不同了,因為生物都能遺傳,所以在他眼裡,我不僅和豬沒區別,和一隻蚊子、一個細菌、一顆樹、一個蘑菇乃至一個SARS病毒都沒什麼區別,因為他會認為我們都實現了IDescendable這個介面(註:descend vi. 遺傳),即我們都是可遺傳的東西,他不會分別研究我們,而會將所有生物作為同類進行研究,在他眼裡沒有人和病毒之分,只有可遺傳的物質和不可遺傳的物質。但至少,我和一塊石頭還是有區別的。
可不幸的事情發生了,某日,地球上出現了一位偉大的人,他叫列寧,他在熟讀馬克思、恩格斯的辯證唯物主義思想巨著後,頗有心得,於是他下了一個著名的定義:所謂物質,就是能被意識所反映的客觀實在。至此,我和一塊石頭、一絲空氣、一條成語和傳輸手機訊號的電磁場已經沒什麼區別了,因為在列寧的眼裡,我們都是可以被意識所反映的客觀實在。如果列寧是一名程式員,他會這麼說:所謂物質,就是所有同時實現了“IReflectabe”和“IEsse”兩個介面的類所產生的執行個體。(註:reflect v. 反映 esse n. 客觀實在)
也許你會覺得我上面的例子像在瞎掰,但是,這正是介面得以存在的意義。物件導向思想和核心之一叫做多態性,什麼叫多態性?說白了就是在某個粒度視圖層面上對同類事物不加區別的對待而統一處理。而之所以敢這樣做,就是因為有介面的存在。像那個遺傳學家,他明白所有生物都實現了IDescendable介面,那隻要是生物,一定有Descend()這個方法,於是他就可以統一研究,而不至於分別研究每一種生物而最終累死。
可能這裡還不能給你一個關於介面本質和作用的直觀印象。那麼在後文的例子和對幾個設計模式的解析中,你將會更直觀體驗到介面的內涵。
3.面向介面編程綜述
通過上文,我想大家對介面和介面的思想內涵有了一個瞭解,那麼什麼是面向介面編程呢?我個人的定義是:在系統分析和架構中,分清層次和依賴關係,每個層次不是直接向其上層提供服務(即不是直接執行個體化在上層中),而是通過定義一組介面,僅向上層暴露其介面功能,上層對於下層僅僅是介面依賴,而不依賴具體類。
這樣做的好處是顯而易見的,首先對系統靈活性大有好處。當下層需要改變時,只要介面及介面功能不變,則上層不用做任何修改。甚至可以在不改動上層代碼時將下層整個替換掉,就像我們將一個WD的60G硬碟換成一個希捷的160G的硬碟,電腦其他地方不用做任何改動,而是把原硬碟拔下來、新硬碟插上就行了,因為電腦其他部分不依賴具體硬碟,而只依賴一個IDE介面,只要硬碟實現了這個介面,就可以替換上去。從這裡看,程式中的介面和現實中的介面極為相似,所以我一直認為,介面(interface)這個詞用的真是神似!
使用介面的另一個好處就是不同組件或層次的開發人員可以並行開工,就像造硬碟的不用等造CPU的,也不用等造顯示器的,只要介面一致,設計合理,完全可以並行進行開發,從而提高效率。
本篇文章先到這裡。最後我想再囉嗦一句:物件導向的精髓是類比現實,這也可以說是我這篇文章的靈魂。所以,多從現實中思考物件導向的東西,對提高系統分析設計能力大有脾益。
下篇文章,我將用一個執行個體來展示介面編程的基本方法。
而第三篇,我將解析經典設計模式中的一些面向介面編程思想,並解析一下.NET分層架構中的面向介面思想。