轉自:http://www.360doc.com/content/13/1114/11/10504424_329106146.shtml
不管以前你是否據說過面向接口,本文所描述的將是一個全新的設計思想叫面向接口。這裏的接口並非代碼中的 interface 關鍵字,思想和語言是沒有直接關係的,只不過有些語言實現一種思想比較方便而已。
在瞭解面向接口前,必須先了解面向對象,由於面向接口是從面向對象根據歷史的經驗衍生出來的一種思想。在面向對象中,一切都是對象,對象擁有獨立性:它必須保持一個內部狀態,而且避免一切外界干擾。因此面向對象要求大部分字段都應該私有的,而後提供有限的公開的接口去訪問這些字段。如:
複製代碼
class 書 {
private string 名字;
public string get名字(){
return this.名字;
}
}
複製代碼
初學者常常會問:爲何不直接公開這個字段,必定要寫個get名字的函數才能獲取到書的名字。面向對象的專家會回答這是爲了類的封裝性(即獨立性)。名字這個字段對外界來講是隻讀不可寫的。
面向對象經過強調對象的獨立性保證了高的代碼重用率,下降了類的學習成本(無需關心內部細節)。可是它卻忘了一個事實:世界萬物都有聯繫。因而,當兩個對象開始有聯繫時,麻煩的問題就出現了。好比如今新增一我的的類:
複製代碼
class 人 {
public void 讀書(書 a){
讀取( a.get名字() )
}
}
複製代碼
人能夠讀書,但書也能夠被讀。那麼讀書這個操做是屬於人仍是屬於書,在面向對象中是沒有區分的。雖然書自己是一個獨立的對象,可是人在讀書時,卻又不得不打破書的封裝性----人須要讀取書的內容和更多細節。抓着封裝思想不放,就不得不爲書增長API才能讓書真正被讀:一個對象提供哪些API是根據需求來決定的。若是需求不少,那麼書的API會很是多,當其餘人去讀這份源碼時,會發現原本一個很簡單的對象,卻有不少不知道幹嗎用的API。不少API是爲了某些需求而寫的,做者將它們塞進這個對象,僅僅爲了更方便訪問私有字段。這種代碼設計其實已經偏離了面向對象的初衷,但對做者而言,完成項目纔是重點。因此他們選擇這種折中的方式:API隨便加,反正達到訪問的目標便可,打破了封裝又如何?因此也有人說:只有有專家纔會在一開始就設計好有哪些對象和API,才能寫出真正面向對象的代碼,這些專家被稱爲軟件構架師。面向對象拒而不談對象之間的聯繫,致使一開始好好的代碼最後變成互相引用的難以維護的代碼。
關於更多面向對象的缺陷,能夠見另外一篇文章:《面向對象中的設計陷阱》
接下來介紹面向接口。面向接口中,一樣的一切都是對象,可是它將對象分紅兩類:生物和非生物。非生物就是沒有生命的對象:好比一本書,一個電腦。在程序中,非生物老是被動的----好比球本身是不會飛的,它只能被踢飛。生物則表明能力的擁有者,它能夠處理非生物,能夠記憶,能夠和其它生物溝通。
好比現實場景:小明的電腦壞了,而後它交給小剛去修。這裏其實有三個對象:小明、小剛、電腦。是人都知道:小明和小剛是生物,電腦是非生物。小明須要作這些事情:1. 記住他有一臺電腦,這是他的私有財產。2. 通知小剛去修電腦,而且將他的私有財產轉交給小剛。小剛須要作這些事情:修電腦(不論是誰的電腦)。電腦是非生物,所以它不能作任何事情。那麼面向接口中,如何將這個現實問題轉換爲代碼表示呢?
原則一:全部的非生物不具有任何封裝性。
以電腦爲例,雖然咱們總將電腦當作一個獨立的總體,但確實是存在一些時刻,它的零件是打散的。電腦自己沒有思考能力,它不能保證本身必定是處於完整的,能用的狀態。所以對非生物來講,它不須要在內部維護一個狀態。可是它能夠有一些必要保護措施,來確保它不會被閒人弄壞,但這個措施不是強制的。就好像你弄壞了電腦,錯在你,不是由於電腦質量差(固然好電腦是不會隨便被搞壞的)。
原則二:全部的生物具備封裝性。
好比小明擁有的電腦是他的私有財產,除非他願意,不然沒人可使用他的電腦。若是小明主動忘記了他有一臺電腦,那麼這臺電腦和小明將失去任何聯繫。
原則三:對事不對人。
好比小明的電腦壞了,他不必定就得交給小剛作,他只要交給一個會修電腦的人來作就行,只不過恰好小剛符合要求而已。
總結如上原則,上述現實問題描述成代碼應該是這樣的:
複製代碼
class 電腦{
public bool 還的仍是壞的;
}
class 小明{
private 電腦 a;
public void 去修電腦(會修電腦的人 b){
b.修電腦(a);
}
}
class 小剛 : 會修電腦的人{
public void 修電腦(電腦 a) {
a.還的仍是壞的 = true;
}
}
複製代碼
以上代碼和麪向對象代碼的區別:
1. 電腦擁有 public 字段:由於電腦是非生物,不須要封裝。
2. 去修電腦的參數是會修電腦的人,而不是小剛。
原則四:能力能夠隨時擴展。
以上三個原則其實並未體現面向接口的優點,真正的優點在於原則四。現實中,你仍是你,可是你的能力是在不斷成長的。面向對象中由於對象是獨立封裝的,即對象先天決定它有哪些能力。可是面向接口中,能力是能夠後期擴展的。
好比原來會修電腦的人只能是小剛,後面小明本身也會修電腦了,那麼,它甚至能夠本身修電腦。而這個修改,並不須要在源碼上進行。由於源碼已經很好體現了這些現實邏輯,無論小明本身會不會修,原來的設計是不變的。一個對象能夠擁有多個能力,被多方使用,能力能夠是先天的,也能夠是後期擴展的。對於上例代碼,如今能夠經過以下代碼爲小明增長修電腦的能力。
複製代碼
extend 小明: 會修電腦的人 {
public void 修電腦(電腦 a){
// 修電腦的邏輯
}
}
複製代碼
講到如今彷佛都沒有提到接口兩個字。接口其實就是一份證書:用於約定一個生物具備哪些能力。上例中的 「會修電腦的人」 就是一種能力的約定-----即它是一個接口。理論上任何能力均可以用接口來描述,但這顯然不現實(生活中不可能爲任何能力都提供一份證書:會燒飯證書?會寫字證書?)所以,咱們使用同一類生物還借代:好比小剛是會修電腦的人,那麼用小剛來借代全部會修電腦的人(就像平時說的鄰居家的孩子來借代擁有各類能力的孩子)。
面向接口中,咱們假設一切生物在起初是沒有任何能力的,全部能力都是後期根據須要再提供的。可是這些能力和這個生物自己的資產是沒有關係的。 html