依賴倒置原則

依賴倒置原則


定義

High level modules should not depend upon low level modules.Both should depend upon abstractions.Abstractions should not depend upon details.Details should depend upon abstractions.
翻譯上面的話有一下三層含義:

  • 高層模塊不應(yīng)該依賴底層模塊赫蛇,兩者都應(yīng)該依賴其抽象
  • 抽象不應(yīng)該依賴其細(xì)節(jié)
  • 細(xì)節(jié)應(yīng)該依賴抽象

高層模塊和低層模塊容易理解痕檬,每一個邏輯的實現(xiàn)都是由原子邏輯組成的暇咆,不可分割的原子邏輯就是低層模塊凯正,原子邏輯的再組裝就是高層模塊饲鄙。那什么是抽象感帅?什么又是細(xì)節(jié)呢门扇?在Java語言中雹有,==抽象就是指接口或抽象類==,兩者都是不能直接被實例化的臼寄;==細(xì)節(jié)就是實現(xiàn)類==霸奕,實現(xiàn)接口或繼承抽象類而產(chǎn)生的類就是細(xì)節(jié),其特點(diǎn)就是可以直接被實例化吉拳,也就是可以加上一個關(guān)鍵字new產(chǎn)生一個對象质帅。依賴倒置原則在Java語言中的表現(xiàn)就是:

  • 模塊間的依賴通過抽象發(fā)生,實現(xiàn)類之間不發(fā)生直接的依賴關(guān)系留攒,其依賴關(guān)系是通過接口或抽象類產(chǎn)生的煤惩;
  • 接口或抽象類不依賴于實現(xiàn)類;
  • 實現(xiàn)類依賴接口或抽象類炼邀。

更加精簡的定義就是“面向接口編程”——OOD(Object-Oriented Design魄揉,面向?qū)ο笤O(shè)計)的精髓之一。

依賴倒置原則優(yōu)點(diǎn)

采用依賴倒置原則可以減少類間的耦合性拭宁,提高系統(tǒng)的穩(wěn)定性什猖,降低并行開發(fā)引起的風(fēng)險,提高代碼的可讀性和可維護(hù)性红淡。

image

下面是源代碼

class Benz {
    public void run(){
        System.out.println("奔馳汽車開始運(yùn)行...");
    }
}

class Driver {
    public void drive(Benz benz){
        benz.run();
    }

}

public class Client {

    public static void main(String args[]){
        Benz benz = new Benz();
        Driver zs = new Driver();
        zs.drive(benz);
    }
}

分析

通過上面的代碼不狮,知道如果需要司機(jī)重新開別的車,顯然需要改司機(jī)類在旱,汽車類摇零,這樣的開發(fā)成本是非常高的,同時也違背了依賴倒置的原則桶蝎,下面引入依賴倒置原則重新設(shè)計開汽車的方法:

image

抽象是對實現(xiàn)的約束驻仅,對依賴者而言谅畅,也是一種契約,不僅僅約束自己噪服,還同時約束自己與外部的關(guān)系毡泻,其目的是保證所有的細(xì)節(jié)不脫離契約的范疇,確保約束雙方按照既定的契約(抽象)共同發(fā)展粘优,只要抽象這根基線在仇味,細(xì)節(jié)就脫離不了這個圈圈,始終讓你的對象做到“言必信雹顺,行必果”丹墨。

依賴的三種寫法

1、構(gòu)造函數(shù)注入

在類中通過構(gòu)造函數(shù)聲明依賴對象嬉愧,按照依賴注入的說法贩挣,這種方式叫做構(gòu)造函數(shù)注入。
按照這種方式的注入没酣,IDriver和Driver的程序如下所示:

public interface IDriver {
    public void drive();
}
public class Drive implements IDriver {

    private ICar car;

    public Drive(ICar car){
        this.car = car;
    }

    public void drive() {
        this.car.run();
    }
}
public class Benz implements ICar{
    public void run(){
        System.out.println("奔馳汽車開始運(yùn)行...");
    }
}
public class Drive implements IDriver {

    private ICar car;

    public Drive(ICar car){
        this.car = car;
    }

    public void drive() {
        this.car.run();
    }
}
public class Client {

    public static void main(String args[]){
        ICar car = new Benz();
        ICar bmw = new BMW();
        IDriver zs = new Drive(car);
        zs.drive();

        zs = new Drive(bmw);
        zs.drive();
    }
}

2王财、set注入

set注入其實就是set方法注入
如下所示:

public interface IDriver {
    // 注入汽車接口
    public void setCar(ICar car);

    public void drive();
}
public class Drive implements IDriver {

    private ICar car;

    // 通過set注入汽車接口
    public void setCar(ICar car) {
        this.car = car;
    }
    // 司機(jī)不用關(guān)心自己駕駛的是什么汽車
    public void drive() {
        this.car.run();
    }
}
public class Benz implements ICar{
    public void run(){
        System.out.println("奔馳汽車開始運(yùn)行...");
    }
}
public class Drive implements IDriver {

    private ICar car;

    public Drive(ICar car){
        this.car = car;
    }

    public void drive() {
        this.car.run();
    }
}
public class Client {

    public static void main(String args[]){
        ICar benz = new Benz();
        ICar bmw = new BMW();
        IDriver zs = new Drive();
        zs.setCar(benz);
        zs.drive();

        zs.setCar(bmw);
        zs.drive();

    }
}

3裕便、接口聲明依賴對象

剛才的分析就是接口聲明依賴對象,代碼如下所示:

public interface IDriver {
    public void drive(ICar car);
}
public class Drive implements IDriver {

    @Override
    public void drive(ICar car) {
        car.run();
    }
}
public interface ICar {
    void run();
}
public class BMW  implements ICar{
    @Override
    public void run() {
        System.out.println("寶馬汽車開始運(yùn)行...");
    }
}
public class Benz implements ICar{
    public void run(){
        System.out.println("奔馳汽車開始運(yùn)行...");
    }
}
public class Client {

    public static void main(String args[]){
        ICar benz = new Benz();
        ICar bmw = new BMW();
        IDriver zs = new Drive();
        zs.drive(benz);

        zs.drive(bmw);
    }
}

總結(jié)

依賴倒置原則的本質(zhì)就是通過抽象(接口或抽象類)使各個類或模塊的實現(xiàn)彼此獨(dú)立哎垦,不互相影響墨闲,實現(xiàn)模塊間的松耦合
所以我們需要遵循以下幾點(diǎn):

  1. 每個類盡量都有接口或抽象類,或者抽象類和接口兩者都具備
    這是依賴倒置的基本要求瞻离,接口和抽象類都是屬于抽象的,有了抽象才可能依賴倒置验辞。
  2. 變量的表面類型盡量是接口或者是抽象類
    很多書上說變量的類型一定要是接口或者是抽象類族购,這個有點(diǎn)絕對化了撑碴,比如一個工具類伟姐,xxxUtils一般是不需要接口或是抽象類的。還有,如果你要使用類的clone方法,就必須使用實現(xiàn)類,這個是JDK提供的一個規(guī)范馅笙。
  3. 任何類都不應(yīng)該從具體類派生
    如果一個項目處于開發(fā)狀態(tài),確實不應(yīng)該有從具體類派生出子類的情況厉亏,但這也不是絕對的董习,因為人都是會犯錯誤的,有時設(shè)計缺陷是在所難免的爱只,因此只要不超過兩層的繼承都是可以忍受的阱飘。特別是負(fù)責(zé)項目維護(hù)的同志,基本上可以不考慮這個規(guī)則,為什么沥匈?維護(hù)工作基本上都是進(jìn)行擴(kuò)展開發(fā)蔗喂,修復(fù)行為,通過一個繼承關(guān)系高帖,覆寫一個方法就可以修正一個很大的Bug缰儿,何必去繼承最高的基類呢?(當(dāng)然這種情況盡量發(fā)生在不甚了解父類或者無法獲得父類代碼的情況下散址。)
  4. 盡量不要覆寫基類的方法
    如果基類是一個抽象類乖阵,而且這個方法已經(jīng)實現(xiàn)了,子類盡量不要覆寫预麸。類間依賴的是抽象瞪浸,覆寫了抽象方法,對依賴的穩(wěn)定性會產(chǎn)生一定的影響吏祸。
  5. 結(jié)合里氏替換原則使用
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末对蒲,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子贡翘,更是在濱河造成了極大的恐慌蹈矮,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鸣驱,死亡現(xiàn)場離奇詭異泛鸟,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)踊东,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門北滥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人闸翅,你說我怎么就攤上這事再芋。” “怎么了缎脾?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵祝闻,是天一觀的道長。 經(jīng)常有香客問我遗菠,道長联喘,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任辙纬,我火速辦了婚禮豁遭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘贺拣。我一直安慰自己蓖谢,他們只是感情好捂蕴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著闪幽,像睡著了一般啥辨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上盯腌,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天溉知,我揣著相機(jī)與錄音,去河邊找鬼腕够。 笑死级乍,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的帚湘。 我是一名探鬼主播玫荣,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼大诸!你這毒婦竟也來了捅厂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤底挫,失蹤者是張志新(化名)和其女友劉穎恒傻,沒想到半個月后脸侥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體建邓,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年睁枕,在試婚紗的時候發(fā)現(xiàn)自己被綠了官边。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡外遇,死狀恐怖注簿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情跳仿,我是刑警寧澤诡渴,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站菲语,受9級特大地震影響妄辩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜山上,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一眼耀、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧佩憾,春花似錦哮伟、人聲如沸干花。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽池凄。三九已至,卻和暖如春鬼廓,著一層夾襖步出監(jiān)牢的瞬間修赞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工桑阶, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留柏副,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓蚣录,卻偏偏與公主長得像割择,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子萎河,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

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