定義:
高層次的模塊不應該依賴于低層次的模塊,兩者都應該依賴于抽象接口;抽象接口不應該依賴于具體實現。而具體實現則應該依賴于抽象接口。依賴倒置原則英文全稱為Dependence Inversion PRinciple,簡稱為DIP。
問題由來:
類A直接依賴類B,假如要將類A改為依賴類C,則必須通過修改類A的代碼來達成。這種場景下,類A一般是高層模塊,負責復雜的業務邏輯;類B和類C是低層模塊,負責基本的原子操作;假如修改類A,會給程序帶來不必要的風險。
解決方案:
將類A修改為依賴接口I,類B和類C各自實現接口I,類A通過接口I間接與類B或者類C發生聯系,則會大大降低修改類A的幾率。
采用依賴倒置原則可以減少類間的耦合性,提高系統的穩定性,減少并行開發引起的風險,提高代碼的可讀性和可維護性。依賴倒置原則的核心就是面向接口編程,理解了面向接口編程也就理解了依賴倒置原則。下面通過一個司機開車的例子簡單說明一下:
有一個奔馳車類,奔馳車可以運行,方法為Run,司機類有一個開奔馳車的方法Drive。司機和奔馳車類的代碼如下所示:
///<summary>/// 奔馳車類///</summary>public class Benz{//奔馳車運行public void Run(){Console.WriteLine("奔馳車開始運行...");}}///<summary>/// 司機類///</summary>public class Driver{public void Drive(Benz benz){benz.Run();}}主函數司機小明開動奔馳車,代碼如下:
class Client{static void Main(string[] args){//一輛奔馳車var benz = new Benz();//司機小明var xiaoming = new Driver();//小明開奔馳xiaoming.Drive(benz);Console.ReadKey();}}上面實現了司機開奔馳車的場景,但是對于實際的業務來說,需求是不斷變化的。在技術上"變更才顯真功夫",只有在"變化"過程中才能知道自己設計或程序是否是松耦合。上面的例子,我們加點要求:司機也要會開寶馬車。要完成這個必須先有個寶馬車類,如下所示:
///<summary>/// 寶馬車類///</summary>public class Bmw{//寶馬車運行public void Run(){Console.WriteLine("寶馬車開始運行...");}}盡管有了寶馬車類,但是司機根本木有開寶馬車的方法。你可能會說,木有那就加上開寶馬車的方法!這樣,是解決了一時的問題,但是還有法拉利、賓利等車呢?因此,是我們的設計出現了問題:司機類和奔馳車類之間是一個緊耦合的關系,其導致的結果就是系統的可維護性大大降低,可讀性降低,兩個相似的類需要閱讀兩個文件,這顯然不可取。還有穩定性:固化的、健壯的才是穩定的。這里只是增加了一個車類就需要修改司機類,這不是穩定性,這是易變性。被依賴者的變更竟然讓依賴者來承擔修改的成本,這樣的依賴關系誰肯承擔!
在實際項目的開發中,要盡可能減少并行開發引起的風險。并行開發最大的風險就是風險擴散,本來只是一段程序的錯誤或異常,逐步波及一個功能,一個模塊,甚至到最后毀壞了整個項目。因為一個團隊,幾十人甚至上百人人開發,各人負責不同的功能模塊,甲負責汽車類的建造,乙負責司機類的建造,在甲沒有完成的情況下,乙是不能完全地編寫代碼的,缺少汽車類,編譯器根本就不會讓你通過!在缺少Benz類的情況下,Driver類能編譯嗎?更不要說是單元測試了!這種相互依存的關系在實際開發中是不被允許的,另一個角度來說這樣開發只能挨個進行修改,并且每一項修改可能牽一發而動全身。這種模式 在現在的大中型項目中已經是完全不能勝任了,一個項目是一個團隊的協作結果,一個人不可能了解所有的業務和所有的技術,要協作就要并行開發,要并行開發就要解決模塊之間的項目依賴關系,然后依賴倒置原則就隆重出場了,呵呵。
依賴倒置原則的核心就是接口,下面我們為車和司機定義兩個接口ICar和IDriver,代碼如下所示:
///<summary>/// 汽車接口///</summary>public interface ICar{void Run();}///<summary>/// 司機接口///</summary>public interface IDriver{void Drive(ICar car);}然后讓上面定義的司機和汽車(寶馬和奔馳)各自繼承自己對應的接口,代碼如下所示:
///<summary>/// 奔馳車類///</summary>public class Benz:ICar{//奔馳車運行public void Run(){Console.WriteLine("奔馳車開始運行...");}}///<summary>/// 寶馬車類///</summary>public class Bmw:ICar{//寶馬車運行public void Run(){Console.WriteLine("寶馬車開始運行...");}}///<summary>/// 司機類///</summary>public class Driver:IDriver{public void Drive(ICar car){car.Run();}}此時的類的結構圖如下所示:

在開發實現業務需求時,我們應該謹記抽象不依賴細節。在這里,汽車和司機的接口都不依賴細節(具體的實現類),看到這應該對依賴倒置原則理解的差不多了吧。
依賴倒置原則是一個指導思想,是通過抽象(接口或抽象類)使各個類或模塊的實現彼此獨立,不互相影響,實現模塊間的松耦合,為更好使用此原則,在實際項目中我們要按如下方法使用:
依賴倒置原則是六個設計原則中最難以實現的原則,它是實現開閉原則的重要途徑,依賴倒置原則沒有實現,就別想實現對擴展開放,對修改關閉。在項目中,大家只要記住是"面向接口編程"就基本上抓住了依賴倒轉原則的核心。順便說一下,實際的項目投產上線和盈利是第一要務,因此設計模式的原則只是提供了指導思想,我們不應該主動去違背,但是限于實際情況不得不違背,否則即便設計得有多么好,架構多么完美,這都是扯淡的事情。一旦超過預期工期或者項目虧本,你老板不高興,然后你也會不高興的…
新聞熱點
疑難解答