一千個人眼裡有一千個哈姆雷特,下麵我嘗試用深入淺出的語言貫穿到“控制反轉”,“依賴註入”,“面向抽象編程”,以及“面向介面編程”這幾個概念。 傳遞參數,關聯(組合&聚合)關係時,要儘量引用高層次的抽象類,使用基類和介面進行變數類型的聲明,參數類型的聲明,數據類型轉換(也是向高層次的抽象類轉),而不要 ...
一千個人眼裡有一千個哈姆雷特,下麵我嘗試用深入淺出的語言貫穿到“控制反轉”,“依賴註入”,“面向抽象編程”,以及“面向介面編程”這幾個概念。
傳遞參數,關聯(組合&聚合)關係時,要儘量引用高層次的抽象類,使用基類和介面進行變數類型的聲明,參數類型的聲明,數據類型轉換(也是向高層次的抽象類轉),而不要用具體的子類。
以上總結為“控制反轉”,也叫“面向抽象編程”。
真到了要使用具體子類的時候,採用“依賴註入”的方式:
- 構造註入,通過構造函數傳入具體類的對象
- setter註入,通過setter方法傳入具體類的對象
- 介面註入,通過在介面中聲明的業務方法,來傳入具體類的對象作為方法的參數
——> 引申到“面向介面編程”的概念,介面的意思就是“如果你是***的話,你能幹嘛?”,介面中定義的是能幹嘛,具體怎麼乾不告訴你,等你是了(即實現該介面)自己去想具體怎麼乾。
介面是抽象概念的一種,當你在面向抽象編程時,傳遞參數,關聯關係,使用的是介面來聲明變數類型,參數類型以及數據類型轉換,而不是具體的類,這就是面向介面編程。
所以,總結出這些概念的關係是,面向對象編程的中心思想是面向抽象編程,而面向介面編程是面向抽象編程的一種。
那麼問題又來了,如果面向介面編程只是面向抽象的一種,那麼另一種是什麼呢?
另一種就是抽象基類,要註意區分這裡的基類的概念,它包含abstract關鍵字的class,也包含普通父類(普通父類也是其眾多子類的抽象化身),這裡主要多說一下abstract class,它很容易與介面混淆,那麼abstract class與介面的區別是什麼?
- abstract class可以包含有方法體的非抽象方法,可以包含任意作用域的成員數據。而介面一般不使用成員數據(即使有也是自動轉為public static final類型),介面的所有方法都是沒有方法體的抽象方法(介面內部不用abstract關鍵字)。
- abstract class是對屬性,行為的抽象,同時也可以有自己的具體方法。而介面只是對行為的抽象,介面更像是abstract class的特殊情況。
- 這兩種不同的抽象概念更好的支持了Java多態(一個基類可以有很多子類is-a,一個類可以實現很多介面like-a)。abstract class仍然是個類,必須是相同種族抽象出來的類,例如動物類,熊貓類,而介面只是對行為的抽象,不管誰實現他,也不管他們是否是一個種族,例如動物和汽車都可以跑,那他們都可以實現具有“跑”行為的介面,對於介面本身來講,他並不關心你是動物還是汽車,他只管定義他的“跑”就行了。
依賴倒轉原則,總結一句話就是定義時用抽象類型(基類或者介面),運行時註入具體類型,開閉原則是目標,里氏代換原則是基礎,依賴倒轉原則是手段。