What
Dependence Inversion Principle(DIP):高層模塊不應該依賴底層模塊,都應該依賴於抽象;抽象不應該依賴於具體,具體依賴於抽象
Why
若高層依賴於底層,那么底層的變動也會導致高層的變動,這就會導致模塊的復用性降低而且大大提高了開發的成本。若是依賴於抽象的話,那么是比較穩定的,底層或者高層的變動都不會互相影響。
How
很多地方引用的個人覺得也非常有代表性的一個例子:公司是福特和本田公司的金牌合作伙伴,現要求開發一套自動駕駛系統,只要汽車上安裝該系統就可以實現無人駕駛,該系統可以在福特和本田車上使用,只要這兩個品牌的汽車使用該系統就能實現自動駕駛。
福特汽車類,包含三個方法,啟動、停止、轉彎
class FordCar { public void Run() { Console.WriteLine("FordCar run"); } public void Stop() { Console.WriteLine("FordCar stop"); } public void Turn() { Console.WriteLine("FordCar turn"); } }
宏達汽車類,包含三個方法,啟動、停止、轉彎
class HondaCar { public void Run() { Console.WriteLine("HondaCar run"); } public void Stop() { Console.WriteLine("HondaCar stop"); } public void Turn() { Console.WriteLine("HondaCar turn"); } }
自動駕駛系統,有三個方法啟動汽車、停止汽車、汽車轉向
class AutoSystem { HondaCar hondaCar = new HondaCar(); FordCar fordCar = new FordCar(); CarType type; public AutoSystem(CarType type) { this.type = type; } public void RunCar() { if (type == CarType.Honda) { hondaCar.Run(); } else if (type == CarType.Ford) { fordCar.Run(); } } public void StopCar() { if (type == CarType.Honda) { hondaCar.Stop(); } else if (type == CarType.Ford) { fordCar.Stop(); } } public void TurnCar() { if (type == CarType.Honda) { hondaCar.Turn(); } else if (type == CarType.Ford) { fordCar.Turn(); } } }
目前來看,是滿足需求的,但是隨着發展業務也在發展,現在如果發展了伙伴,需要對其他品牌的汽車添加自動駕駛系統,比如紅旗、奇瑞等品牌,那么如果沿用以前的方式,就需要去修改AutoSystem了,先增加兩個新的品牌汽車的對象,然后在啟動汽車、停止汽車、汽車轉向中進行修改增加分支語句對不同的品牌來進行判斷然后加上各種操作,這樣就違背的OCP,而且復雜的分支語句也會容易造成錯誤,如果以后再繼續擴展其他的品牌的話,那么這樣的程序肯定是不易於維護的,程序的健壯性是較差的,大大的增加了開發的成本。那么敏感的同學已經看出來,既然不同的汽車品牌之間都擁有相同的行為,那么為什么不定義一個接口呢?現在我們先來定義一個接口,然后將各個品牌的汽車實現這個接口實現,那么在AutoSystem中我們就可以針對定義的接口操作了。
interface ICar { void Run(); void Stop(); void Turn(); }
自動駕駛系統也就是高層模塊現在針對的是這個抽象的接口,無論什么汽車,只要實現了ICar接口,就能進行相關的操作。
class AutoSystem { ICar car; public AutoSystem(ICar car) { this.car = car; } public void RunCar() { car.Run(); } public void StopCar() { car.Stop(); } public void TurnCar() { car.Turn(); } }
福特汽車類也就是底層模塊,實現了ICar接口,現在依賴的是抽象的接口
class FordCar : ICar { public void Run() { Console.WriteLine("FordCar run"); } public void Stop() { Console.WriteLine("FordCar stop"); } public void Turn() { Console.WriteLine("FordCar turn"); } }
宏達汽車類也就是底層模塊,實現了ICar接口,現在依賴的是抽象的接口
class HondaCar : ICar { public void Run() { Console.WriteLine("HondaCar run"); } public void Stop() { Console.WriteLine("HondaCar stop"); } public void Turn() { Console.WriteLine("HondaCar turn"); } }
當高層模塊依賴底層的時候,那么高層的復用性就較差,就如上例所說的增加汽車品牌種類。如果高層與底層都是依賴於抽象的話,那么高層復用性就較好,因為通過繼承象出來的接口實現多態,那么復用的地方就多了,這樣的設計無疑是較為穩定的。