C#實(shí)現(xiàn)六大設(shè)計(jì)原則之依賴倒置原則
依賴倒置原則(DIP)定義:
高層模塊不應(yīng)該依賴低層模塊,二者都應(yīng)該依賴其抽象;抽象不應(yīng)該依賴細(xì)節(jié);細(xì)節(jié)應(yīng)該依賴抽象。
問題由來:
類A直接依賴類B,假如要將類A改為依賴類C,則必須通過修改類A的代碼來達(dá)成。這種場(chǎng)景下,類A一般是高層模塊,
負(fù)責(zé)復(fù)雜的業(yè)務(wù)邏輯;類B和類C是低層模塊,負(fù)責(zé)基本的原子操作;假如修改類A,會(huì)給程序帶來不必要的風(fēng)險(xiǎn)。
解決方案:
將類A修改為依賴接口I,類B和類C各自實(shí)現(xiàn)接口I,類A通過接口I間接與類B或者類C發(fā)生聯(lián)系,則會(huì)大大降低修改類A的幾率。
ps:
依賴倒置原則基于這樣一個(gè)事實(shí):相對(duì)于細(xì)節(jié)的多變性,抽象的東西要穩(wěn)定的多。以抽象為基礎(chǔ)搭建起來的架構(gòu)比以細(xì)節(jié)為基礎(chǔ)
搭建起來的架構(gòu)要穩(wěn)定的多。抽象指的是接口或者抽象類,細(xì)節(jié)就是具體的實(shí)現(xiàn)類,使用接口或者抽象類的目的是制定
好規(guī)范和契約,而不去涉及任何具體的操作,把展現(xiàn)細(xì)節(jié)的任務(wù)交給他們的實(shí)現(xiàn)類去完成。
依賴倒置原則的核心思想是面向接口編程,用一個(gè)例子來說明面向接口編程比相對(duì)于面向?qū)崿F(xiàn)編程好在什么地方。
舉個(gè)生活中的例子, 我們每天下班, 可能為了方便亦或鍛煉身體, 選擇騎單車回家, 對(duì)于現(xiàn)在單車, 又有各種各樣: mobike, ofo, 小藍(lán), 小鳴等等...
(用C#代碼表達(dá)) 定義3個(gè)實(shí)現(xiàn), 分別對(duì)應(yīng)的是各種單車品牌。
public class BlueGoGo { public void Go() { Console.WriteLine("騎的是小藍(lán)單車"); } } public class Ofo { public void Go() { Console.WriteLine("騎的是小黃單車"); } } public class Mobike { public void Go() { Console.WriteLine("騎的是摩拜單車"); } }
然后再定義一個(gè)騎行類(Ride)
//騎行類 public class Ride { //掃碼小藍(lán)騎車 public void ScanCodeByBlueGoGo() { BlueGoGo blue = new BlueGoGo(); blue.Go(); } //掃碼摩拜單騎車 public void ScanCodeByMoBike() { Mobike mo = new Mobike(); mo.Go(); } //掃碼小黃騎車 public void ScanCodeByOfo() { Ofo ofo = new Ofo(); ofo.Go(); } }
現(xiàn)在看上去確實(shí)也沒什么問題, 所以調(diào)用一下, 一切正常
仔細(xì)看看, 這個(gè)代碼確實(shí)有問題, 針對(duì)上面所講的依賴倒置原則
<類A直接依賴類B, 假如要將類A改為依賴類C,則必須通過修改類A的代碼來達(dá)成。這種場(chǎng)景下,類A一般是高層模塊,負(fù)責(zé)復(fù)雜的業(yè)務(wù)邏輯;類B和類C是低層模塊,負(fù)責(zé)基本的原子操作;假如修改類A,會(huì)給程序帶來不必要的風(fēng)險(xiǎn)。>
正如例子中的 騎行類(Ride) 正是依賴BlueGoGo,MoBike,Ofo類, 如果現(xiàn)在 Ride類要新增一個(gè)小鳴單車, 則我們必須要修改Ride的代碼,同是添加一個(gè)XiaoMing的類達(dá)到效果。
//騎行類 public class Ride { //掃碼小藍(lán)騎車 public void ScanCodeByBlueGoGo() { BlueGoGo blue = new BlueGoGo(); blue.Go(); } //掃碼摩拜單騎車 public void ScanCodeByMoBike() { Mobike mo = new Mobike(); mo.Go(); } //掃碼小黃騎車 public void ScanCodeByOfo() { Ofo ofo = new Ofo(); ofo.Go(); } /* * 該功能位新增的小鳴單車, 必須修改Ride類 */ public void ScanCodeByXiaoMing() { XiaoMing xming = new XiaoMing(); xming.Go(); } }
像MoBike, BlueGoGo, Ofo, XiaoMing 這些類, 他們都屬于底層模塊, 負(fù)責(zé)基本的騎車的動(dòng)作, 按照依賴倒置的原則, 則不應(yīng)該修改A, 否則如果在業(yè)務(wù)量很大的情況下, 則會(huì)給程序帶來不必要的潛在風(fēng)險(xiǎn)。
用依賴導(dǎo)致的思想怎么去實(shí)現(xiàn) 新增小鳴單車而不對(duì)高層模塊進(jìn)行修改?
1.將單車的每個(gè)Go動(dòng)作都抽象起來, 分別讓他們?nèi)プ龈髯缘膶?shí)現(xiàn)。
//修改位抽象的車類 public abstract class abstarctBike { public abstract void Go(); } public class BlueGoGo: abstarctBike { public override void Go() { Console.WriteLine("騎的是小藍(lán)單車"); } } public class Ofo : abstarctBike { public override void Go() { Console.WriteLine("騎的是小黃單車"); } } public class Mobike : abstarctBike { public override void Go() { Console.WriteLine("騎的是摩拜單車"); } } public class XiaoMing : abstarctBike { public override void Go() { Console.WriteLine("騎的是小明單車"); } }
這時(shí), 我們?cè)侔羊T行類(Ride)進(jìn)行改造, 將原有的ScanCodeXXX 都棄用, 用一個(gè)全新的ScanCode提供一個(gè)抽象類型。
//騎行類 public class Ride { // public void ScanCode(abstarctBike bike) { bike.Go(); } /* * 以下位之前棄用的模式 */ //掃碼小藍(lán)騎車 public void ScanCodeByBlueGoGo() { BlueGoGo blue = new BlueGoGo(); blue.Go(); } //掃碼摩拜單騎車 public void ScanCodeByMoBike() { Mobike mo = new Mobike(); mo.Go(); } //掃碼小黃騎車 public void ScanCodeByOfo() { Ofo ofo = new Ofo(); ofo.Go(); } /* * 該功能位新增的小鳴單車, 必須修改Ride類 */ public void ScanCodeByXiaoMing() { XiaoMing xming = new XiaoMing(); xming.Go(); } }
現(xiàn)在, 我們?cè)僬{(diào)用, 只要指定給Ride對(duì)象ScanCode執(zhí)行的類型就可以實(shí)現(xiàn)騎行動(dòng)作。
這樣修改后,無論以后怎樣擴(kuò)展單車類,都不需要再修改Ride類了。這只是一個(gè)簡(jiǎn)單的例子,實(shí)際情況中,代表高層模塊的Ride類將負(fù)責(zé)完成主要的業(yè)務(wù)邏輯,
一旦需要對(duì)它進(jìn)行修改,引入錯(cuò)誤的風(fēng)險(xiǎn)極大。所以遵循依賴倒置原則可以降低類之間的耦合性,提高系統(tǒng)的穩(wěn)定性,降低修改程序造成的風(fēng)險(xiǎn)。
在實(shí)際編程中,我們一般需要做到如下3點(diǎn):
- 低層模塊盡量都要有抽象類或接口,或者兩者都有。
- 變量的聲明類型盡量是抽象類或接口。
- 使用繼承時(shí)遵循里氏替換原則。
依賴倒置原則的核心就是要我們面向接口編程,理解了面向接口編程,也就理解了依賴倒置。
到此這篇關(guān)于C#實(shí)現(xiàn)六大設(shè)計(jì)原則之依賴倒置原則的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- C#面向?qū)ο笤O(shè)計(jì)原則之組合/聚合復(fù)用原則
- C#面向?qū)ο笤O(shè)計(jì)原則之接口隔離原則
- C#面向?qū)ο笤O(shè)計(jì)原則之里氏替換原則
- C#面向?qū)ο笤O(shè)計(jì)原則之單一職責(zé)原則
- C#面向?qū)ο笤O(shè)計(jì)原則之開閉原則
- C#實(shí)現(xiàn)六大設(shè)計(jì)原則之迪米特法則
- C#實(shí)現(xiàn)六大設(shè)計(jì)原則之接口隔離原則
- C#實(shí)現(xiàn)六大設(shè)計(jì)原則之里氏替換原則
- C#實(shí)現(xiàn)六大設(shè)計(jì)原則之單一職責(zé)原則
- 淺談C#六大設(shè)計(jì)原則
- C#編程之依賴倒置原則DIP
相關(guān)文章
C#使用ScrapySharp快速?gòu)木W(wǎng)頁(yè)采集數(shù)據(jù)
這篇文章介紹了使用ScrapySharp快速?gòu)木W(wǎng)頁(yè)采集數(shù)據(jù)的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06Unity技術(shù)手冊(cè)之Slider滑動(dòng)器使用實(shí)例詳解
這篇文章主要為大家介紹了Unity技術(shù)手冊(cè)之Slider滑動(dòng)器使用實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11C#調(diào)用usb攝像頭的實(shí)現(xiàn)方法
這篇文章主要介紹了C#調(diào)用usb攝像頭的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02C#實(shí)現(xiàn)金額轉(zhuǎn)換成中文大寫金額
這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)金額轉(zhuǎn)換成中文大寫金額,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08C#把數(shù)組中的某個(gè)元素取出來放到第一個(gè)位置的實(shí)現(xiàn)方法
這篇文章主要介紹了C#把數(shù)組中的某個(gè)元素取出來放到第一個(gè)位置的實(shí)現(xiàn)方法,涉及C#針對(duì)數(shù)組的常見操作技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2014-12-12