一、什麼是依賴倒置原則
一種表述:
抽象不應當依賴於細節;細節應當依賴於抽象。
另一種表述:
要針對介面編程,不要針對實現編程。
針對介面編程的意思就是說,應當使用Java介面和抽象Java類進行變數的型別宣告、參量的型別宣告、方法的傳回型別聲明,以及資料類型的轉換等。
不要針對實現編程的意思就是說,不應當使用具體Java類進行變數的型別宣告、參量的型別宣告、方法的傳回型別聲明,以及資料類型的轉換等。
二、為什麼要倒置
傳統的過程性系統的設計方法傾向於使高層次的模組依賴於低層次的模組,抽象層次依賴於具體層次。倒置原則就是要把這個錯誤的依賴關係倒轉過來。
抽象層次包含的是應用程式的商務邏輯和宏觀的、對整個系統來說重要的戰略性決定,是必然性的體現;而具體層次則含有一些次要的與實現有關的演算法和邏輯,以及戰術性的決定,帶有相當大的偶然性選擇。具體層次的代碼經常會有變動,不能避免錯誤。抽象層次依賴於具體層次,使許多具體層次的細節的演算法變化立即影響到抽象層次的宏觀的商務邏輯,倒置微觀決定宏觀,戰術決定戰略,偶然決定必然,這不是很荒唐嗎。
三、再看Factory 方法模式
按照依賴倒置原則,用戶端應該依賴於對象的抽象類別型而不是它的具體類型,但是在Java中使用new建立一個具體對象執行個體時必須調用具體類的構造方法,所以Java語言給出的類的執行個體無法做到只依賴於抽象類別型。但是我們可以做到部分依賴,因為Java中有多態的特性。例如A是一個抽象類別,B是繼承自A的一個具體子類,我們可以寫如下的代碼:
B b = new B();
這是一個完全依賴具體的不好的寫法,我們可以利用多態性寫成下面這樣:
A a = new B();
這樣就變成了部分依賴,前邊的A是依賴於抽象的,這樣當B換成其他的繼承自A的子類的時候,其他的程式是不會受到影響的。即使是這樣還是沒有做到完全依賴於抽象,在設計模式中前邊講過的Factory 方法模式就解決了這個問題。
Factory 方法模式將建立一個對象的工程封裝起來,用戶端僅僅得到這個執行個體化的結果,以及這個執行個體的抽象類別型,當然Factory 方法也不能避免要用new建立對象的限制,但是原廠模式將這個違反規則的做法延遲到了具體工廠角色中。將違反規則的做法孤立於易於控制的地方。
四、執行個體分析
這是一個銀行賬戶的例子,一個Account包含兩個部分,AccountType和AccountStatus,這兩個類都是抽象類別,這兩個類分別有兩個具體的子類,Account在使用的是抽象類別而不是子類,從而在Account的角度上是符合依賴倒置原則的。
package com.designphilsophy.dip;/** * 賬戶 * @author xingjiarong * */public class Account { private AccountType accountType; private AccountStatus accountStatus; public Account(AccountType acctType) { // write your code here } public void deposit(float amt) { // write your code here }}
package com.designphilsophy.dip;/** * 賬戶的狀態是開的狀態還是超支狀態 * @author xingjiarong * */public abstract class AccountStatus{ public abstract void sendCorrespondence();}
package com.designphilsophy.dip;/** * 賬戶的類型是儲蓄卡還是支票 * * @author xingjiarong * */public abstract class AccountType { public abstract void deposit(float amt);}
package com.designphilsophy.dip;/** * 支票 * * @author xingjiarong * */public class Checking extends AccountType { public void deposit(float amt) { // write your code here }}
package com.designphilsophy.dip;/** * 儲蓄卡 * * @author xingjiarong * */public class Savings extends AccountType { public void deposit(float amt) { // write your code here }}
package com.designphilsophy.dip;/** * 開狀態 * * @author xingjiarong * */public class Open extends AccountStatus { public void sendCorrespondence() { // write your code here }}
在這個例子中,Account類依賴於AccountType和AccountStatus,但是這兩個類都是抽象類別,如果我們想再添加一個新的狀態超支狀態的話,不會對其他的類造成影響。
package com.designphilsophy.dip;/** * 超支狀態 * @author xingjiarong * */public class Overdrawn extends AccountStatus { public void sendCorrespondence() { // write your code here }}
源碼下載:http://download.csdn.net/detail/xingjiarong/9309387