DIP 依賴倒置原則

Dependency Inversion Principle

動(dòng)機(jī)

我們?cè)O(shè)計(jì)軟件應(yīng)用時(shí),可以將完成基礎(chǔ)操作(磁盤訪問硕盹,網(wǎng)絡(luò)協(xié)議...等)的類稱為低層類墨状,將封裝復(fù)雜邏輯(業(yè)務(wù)流程...等)的類稱為高層類。后者依賴底層類纷跛。一種實(shí)現(xiàn)這種結(jié)構(gòu)的自然方式是編寫底層類谱邪,完成后再編寫高層類。由于高層類是基于其他類來定義的驰徊,這種做法似乎合乎邏輯笤闯。不過這個(gè)設(shè)計(jì)不靈活。如果我們替換掉一個(gè)低層類棍厂,會(huì)發(fā)生什么颗味?

我們來看看經(jīng)典的復(fù)制模塊例子,復(fù)制模塊從鍵盤讀取字符牺弹,然后寫入到打印設(shè)備中浦马。Copy 類是包含代碼邏輯的高層類。KeyboardReaderPrinterWriter 是低層類例驹。

在糟糕的設(shè)計(jì)中捐韩,高層類會(huì)直接使用并且嚴(yán)重的依賴低層類退唠。在這種情況下鹃锈,如果我們想改變?cè)O(shè)計(jì),將輸出導(dǎo)向新的 FileWriter 類上瞧预,我們將不得不修改Copy 類屎债。(我們假設(shè)這是一個(gè)超級(jí)復(fù)雜的類仅政,其中有一堆邏輯并且真地很難測(cè)試)。

為了避免這些問題盆驹,我們可以在高層類和低層類之間引入一個(gè)抽象層圆丹。由于高層模塊包含復(fù)雜的邏輯,它們不能依賴低層模塊躯喇,所以新引入的抽象層不能基于低層模塊構(gòu)建辫封。而低層模塊應(yīng)基于抽象層創(chuàng)建。

根據(jù)此原則廉丽,設(shè)計(jì)類結(jié)構(gòu)的方式則要從高層模塊到低層模塊: 高層類 --> 抽象層 --> 低層類

目的

高層模塊不應(yīng)依賴低層模塊倦微。兩則都應(yīng)該依賴抽象。
抽象不能依賴細(xì)節(jié)正压。細(xì)節(jié)應(yīng)該依賴抽象欣福。

例子

以下是一個(gè)違背了 DIP 的例子 。我們有一個(gè)高層類 Manager 和一個(gè)底層類 Worker 焦履。 我們需要給應(yīng)用增加一個(gè)新模塊來模擬由于雇傭新的熟練工導(dǎo)致的公司組織架構(gòu)的調(diào)整拓劝。為此我們建了一個(gè)新類 SuperWorker

我們假設(shè) Manager 類相當(dāng)復(fù)雜嘉裤,其中包含特別復(fù)雜的邏輯≈A伲現(xiàn)在我們?yōu)榱艘脒@個(gè)新類 SuperWorker,不得不對(duì)其進(jìn)行修改屑宠。我們看看以下幾個(gè)缺點(diǎn):

  • 我們得修改 Manager 類(記住牧抵,它是個(gè)復(fù)雜類,需要花費(fèi)一翻時(shí)間和功夫來完成這些修改)
  • 可能會(huì)影響Manager 中現(xiàn)有的功能
  • 必須重寫單元測(cè)試

所有這些問題都需要耗費(fèi)很多時(shí)間侨把,而且可能引入新錯(cuò)誤到舊有功能里犀变。如果應(yīng)用一開始設(shè)計(jì)的時(shí)候就遵循 DIP ,結(jié)果可能就不一樣了秋柄。這通常表示获枝,我們?cè)O(shè)計(jì)管理類成一個(gè) IWorker 接口,并且 Worker 類實(shí)現(xiàn) IWorker 接口骇笔。當(dāng)需要添加一個(gè) SuperWorker 省店,我們所要做的只是讓其實(shí)現(xiàn) IWorker 接口。不需要在現(xiàn)有類中做其他改動(dòng)笨触。

// Dependency Inversion Principle  -- Bad Example
class Worker{
    public void work(){
        // ... working  干活
    }
}
class Manager{
    Worker worker;

    public void setWorker(Worker w){
        this.worker = w;
    }

    public void manage(){
        this.worker.work();
    }
}

class SuperWorker{
    public void work(){
        // ... working much more 干的更多
    }
}

以下是遵循 DIP 原則的代碼懦傍。新設(shè)計(jì)中,添加了一個(gè)新抽象層 IWorker接口÷樱現(xiàn)在粗俱,上面的那些問題就被解決了(不用修改高層邏輯):

  • 添加 SuperWorker 的時(shí)候不需要修改 Manager
  • 由于不用修改 Manager ,影響其中現(xiàn)有功能的風(fēng)險(xiǎn)降到最低
  • 不用重新編寫 Manager 的單元測(cè)試
 // Dependency Inversion Principle  -- Good example
interface IWorker{
    public void work();
}

class Worker implements IWorker{
    public void work(){
        // ... working 
    }
}

class SuperWorker implements IWorker{
    public void work(){
        // ... working much more
    }
}

class Manager{
    IWorker worker;

    public void setWorker(IWorker w){
        this.worker = w;
    }

    public void manage(){
        this.worker.work();
    }
}

總結(jié)

當(dāng)應(yīng)用這個(gè)原則時(shí)虚吟,高層類不再直接和低層類交互寸认,它們以接口作為抽象層签财。在這種情況下,在高層類中實(shí)例化低層類(如果需要的話)就不能通過 new 操作符來完成了偏塞。相反唱蒸,可以使用一些創(chuàng)建型設(shè)計(jì)模式,如工廠模式灸叼,抽象工廠神汹,原型模式。

模版模式就是 DIP 應(yīng)用的一個(gè)具體例子古今。

當(dāng)然慎冤,使用這個(gè)原則需要你花點(diǎn)力氣的,因?yàn)樗枰憔S護(hù)更多的類和接口沧卢∫系蹋總之,它會(huì)引入更多復(fù)雜的代碼但狭,但是更加靈活披诗。不要盲目的將此原則應(yīng)用到所有的類和模塊中。如果我們的一個(gè)類功能很可能在以后都不會(huì)變立磁,那么也就不需要應(yīng)用此原則了呈队。

上一篇: 開發(fā)-關(guān)閉原則
下一篇: 接口隔離原則
目錄: http://www.reibang.com/p/af861220a6cc

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市唱歧,隨后出現(xiàn)的幾起案子宪摧,更是在濱河造成了極大的恐慌,老刑警劉巖颅崩,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件几于,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡沿后,警方通過查閱死者的電腦和手機(jī)沿彭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來尖滚,“玉大人喉刘,你說我怎么就攤上這事∑崤” “怎么了睦裳?”我有些...
    開封第一講書人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)撼唾。 經(jīng)常有香客問我廉邑,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任鬓催,我火速辦了婚禮肺素,結(jié)果婚禮上恨锚,老公的妹妹穿的比我還像新娘宇驾。我一直安慰自己,他們只是感情好猴伶,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開白布课舍。 她就那樣靜靜地躺著,像睡著了一般他挎。 火紅的嫁衣襯著肌膚如雪筝尾。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,573評(píng)論 1 305
  • 那天办桨,我揣著相機(jī)與錄音筹淫,去河邊找鬼。 笑死呢撞,一個(gè)胖子當(dāng)著我的面吹牛损姜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播殊霞,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼摧阅,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了绷蹲?” 一聲冷哼從身側(cè)響起棒卷,我...
    開封第一講書人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎祝钢,沒想到半個(gè)月后比规,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拦英,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年苞俘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片龄章。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡吃谣,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出做裙,到底是詐尸還是另有隱情岗憋,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布锚贱,位于F島的核電站仔戈,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜监徘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一晋修、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧凰盔,春花似錦墓卦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至尿庐,卻和暖如春忠怖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背抄瑟。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工凡泣, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人皮假。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓鞋拟,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親钞翔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子严卖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容