六大設(shè)計原則之依賴倒置原則(DIP)

很多初學(xué)編程的小伙伴在編程時會發(fā)現(xiàn)兴猩,自己寫的類總是頻繁的用到(依賴)其他類鞭衩,一旦被依賴的類需要修改敲茄,那么其他的類也統(tǒng)統(tǒng)都要修改一遍,讓人感覺煩不勝煩副签。若是小型的程序也緊緊是覺得煩而已遥椿,可一旦是大型的工程,這種強(qiáng)耦合的程序一旦有某一個細(xì)節(jié)放生改變淆储,那是砸電腦的心都有修壕。

各個具體類之間發(fā)生了直接的依賴關(guān)系,使得這些類緊緊地耦合在了一起遏考,從而降低了程序的穩(wěn)定性、可維護(hù)性和可讀性蓝谨。要解決這個問題灌具,我們可以用一些方法來將這些程序解耦,降低其耦合性譬巫。這種方法就是我即將要講到的依賴倒置原則(Dependence Inversion Principle ,DIP)咖楣。

定義

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)該依賴抽象。

也就是說咕缎,高層模塊珠十、低層模塊、細(xì)節(jié)都應(yīng)該依賴抽象凭豪。

  • 低層模塊:組成一個大邏輯的顆粒原子邏輯焙蹭。
  • 高層模塊:顆粒原子邏輯組成的模塊。
  • 抽象:指接口或抽象類嫂伞,兩者都不能被實例化孔厉。
  • 細(xì)節(jié):實現(xiàn)類拯钻,實現(xiàn)接口或繼承抽象類而產(chǎn)生的類就是細(xì)節(jié),其特點就是可以直接被實例化撰豺。

java的精髓

依賴倒置原則在java中的三種含義:

  1. 模塊間的依賴通過抽象發(fā)生粪般,實現(xiàn)類之間不發(fā)生直接的依賴關(guān)系,其依賴關(guān)系是通過接口或抽象類產(chǎn)生的污桦;
  2. 接口或抽象類不依賴于實現(xiàn)類亩歹;
  3. 實現(xiàn)類依賴接口或抽象類。

這三種含義在java的精髓之一——面向接口編程中體現(xiàn)得淋漓盡致寡润。

用與不用依賴倒置原則的對比

既然一開始就說到不用依賴倒置原則有多糟糕捆憎,那么下面我們就用一個簡單的程序來證明一下。

不使用依賴倒置原則:

程序1

/**
* 大眾汽車類
* @author 葉漢偉
*/
public class DaZhong {
    public void run(){
        System.out.println("開大眾汽車");
    }
}

/**
 * 司機(jī)類
 * @author 葉漢偉
 */
public class Driver {
    public void drive(DaZhong daZhong){
        daZhong.run();
    }
}

public class Client {
    public static void main(String[] args){
        Driver Tom=new Driver();
        DaZhong daZhong=new DaZhong();
        Tom.drive(daZhong);
    }
}

看上去沒什么嘛梭纹,這不是好好的嗎躲惰?好像也是哦。那么既然司機(jī)會開大眾汽車变抽,那應(yīng)該會開寶馬吧础拨。我們讓它開一下寶馬試試。

先生產(chǎn)一輛寶馬給他:

程序2

/**
 * 寶馬車類
 * @author 葉漢偉
 */
public class BaoMa {
    public void run(){
        System.out.println("開寶馬車");
    }
}

當(dāng)我們要讓司機(jī)開寶馬的時候绍载,他確開不了诡宗,程序報錯了。感情他考的是大眾駕照击儡,有寶馬都開不了啊塔沃。

其實要讓司機(jī)開寶馬車也容易,把司機(jī)類開車方法的參數(shù)改一下就成了唄阳谍。的確可以蛀柴。但又想想,現(xiàn)在知識多了個寶馬車矫夯,如果我再多個奔馳鸽疾、本田什么的,那不就是要經(jīng)常改训貌,大改特改制肮?對于大型的項目來說,這是致命的递沪。

使用依賴倒置原則

那么接下來豺鼻,我們看一下使用依賴倒置原則有什么優(yōu)勢。

程序3

/**
 * 車子接口
 * @author 葉漢偉
 */
public interface ICar {
    public void run();
}

/**
 * 大眾汽車類
 * @author 葉漢偉
 */
public class DaZhong implements ICar{
    public void run(){
        System.out.println("開大眾汽車");
    }
}

/**
 * 寶馬車類
 * @author 葉漢偉
 */
public class BaoMa implements ICar{
    public void run(){
        System.out.println("開寶馬車");
    }
}

/**
 * 司機(jī)接口
 * @author 葉漢偉
 */
public interface IDriver {
    public void drive(ICar car);
}

/**
 * 司機(jī)類
 * @author 葉漢偉
 */
public class Driver implements IDriver{
    public void drive(ICar car){
        car.run();
    }
}

public class Client {
    public static void main(String[] args){
        IDriver Tom=new Driver();
        //Tom開大眾汽車
        ICar daZhong=new DaZhong();
        Tom.drive(daZhong);
        //Tom開寶馬
        ICar baoMa=new BaoMa();
        Tom.drive(baoMa);
    }
}

看款慨,現(xiàn)在不僅可以開大眾拘领,而且可以開寶馬了。要還有什么本田樱调、奔馳汽車约素,一個drive方法都能開届良,而開其他的車只需要修改一下客戶端就可以了。

上面的程序在實現(xiàn)類之間不發(fā)生依賴關(guān)系圣猎,他們的依賴關(guān)系是在接口處發(fā)生的士葫,這樣就可以大大的降低了類之間的耦合。其實這里不僅用到了依賴倒置原則送悔,還用到了里氏替換原則慢显,從類Client中可以看出來。

實現(xiàn)依賴的三種方法

對象的依賴關(guān)系可以通過三種方法來實現(xiàn):

  1. 接口聲明依賴對象
  2. 構(gòu)造函數(shù)傳遞依賴對象
  3. setter方法傳遞依賴對象

接口聲明依賴對象

在接口處就聲明了依賴的對象欠啤。如程序3中的司機(jī)接口IDriver荚藻,其方法drive()的形參是ICar類型的。那么我們可以說IDrive與ICar放生了依賴關(guān)系洁段,這個依賴對象在接口處已經(jīng)聲明了应狱。接口聲明依賴的方法也叫接口注入

構(gòu)造函數(shù)傳遞依賴對象

在類中通過構(gòu)造函數(shù)聲明依賴對象祠丝。具體實現(xiàn)如下:

程序4

/**
 * 司機(jī)接口
 * @author 葉漢偉
 */
public interface IDriver {
    public void drive();
}

/**
 * 司機(jī)類
 * @author 葉漢偉
 */
public class Driver implements IDriver{
private ICar car;
//通過構(gòu)造函數(shù)注入依賴對象
public Driver(ICar car){
    this.car=car;
}
    public void drive(){
        this.car.run();
    }
}

如果我們想要司機(jī)開寶馬車疾呻,只需要將寶馬車對象傳入構(gòu)造函數(shù)即可。這種方法又叫做構(gòu)造函數(shù)注入写半。

setter方法傳遞依賴對象

這種方法通過在抽象中增加一個setter方法實現(xiàn)岸蜗。具體實現(xiàn)如下:

程序5

/**
 * 司機(jī)接口
 * @author 葉漢偉
 */
public interface IDriver {
public void setCar(ICar car);
    public void drive();
}

/**
 * 司機(jī)類
 * @author 葉漢偉
 */
public class Driver implements IDriver{
private ICar car;
//setter方法傳遞依賴對象
public void setCar(ICar car){
    this.car=car;
}
    public void drive(){
        this.car.run();
    }
}

若要司機(jī)開那種車,只需要將車子的對象通過Driver對象的setCar()方法傳入即可叠蝇。這種方法又叫setter依賴注入璃岳。

總結(jié)

通過依賴倒置原則,我們可以實現(xiàn)模塊中的松耦合悔捶。具體來說總結(jié)為一下幾點規(guī)則:

  • 每個類盡量都有接口或抽象類矾睦,或者抽象類和接口兩者都具備
  • 變量的表面類型盡量是接口或者是抽象類
  • 任何類都不應(yīng)該從具體類派生
  • 盡量不要覆寫基類的方法
  • 結(jié)合里氏替換原則使用

還沒有形成面向接口編程的java學(xué)習(xí)者們,趕緊將這個規(guī)則用起來吧炎功,用過一段之間,你會感覺水平飆升缓溅,在代碼間游走更加柔韌有余蛇损。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市坛怪,隨后出現(xiàn)的幾起案子淤齐,更是在濱河造成了極大的恐慌,老刑警劉巖袜匿,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件更啄,死亡現(xiàn)場離奇詭異,居然都是意外死亡居灯,警方通過查閱死者的電腦和手機(jī)祭务,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進(jìn)店門内狗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人义锥,你說我怎么就攤上這事柳沙。” “怎么了拌倍?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵赂鲤,是天一觀的道長。 經(jīng)常有香客問我柱恤,道長数初,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任梗顺,我火速辦了婚禮泡孩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘荚守。我一直安慰自己珍德,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布矗漾。 她就那樣靜靜地躺著锈候,像睡著了一般。 火紅的嫁衣襯著肌膚如雪敞贡。 梳的紋絲不亂的頭發(fā)上泵琳,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天,我揣著相機(jī)與錄音誊役,去河邊找鬼获列。 笑死,一個胖子當(dāng)著我的面吹牛蛔垢,可吹牛的內(nèi)容都是我干的击孩。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼鹏漆,長吁一口氣:“原來是場噩夢啊……” “哼巩梢!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起艺玲,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤括蝠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后饭聚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體忌警,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年秒梳,在試婚紗的時候發(fā)現(xiàn)自己被綠了法绵。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片箕速。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖礼烈,靈堂內(nèi)的尸體忽然破棺而出弧满,到底是詐尸還是另有隱情,我是刑警寧澤此熬,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布庭呜,位于F島的核電站,受9級特大地震影響犀忱,放射性物質(zhì)發(fā)生泄漏募谎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一阴汇、第九天 我趴在偏房一處隱蔽的房頂上張望数冬。 院中可真熱鬧,春花似錦搀庶、人聲如沸拐纱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秸架。三九已至,卻和暖如春咆蒿,著一層夾襖步出監(jiān)牢的瞬間东抹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工沃测, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留缭黔,地道東北人。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓蒂破,卻偏偏與公主長得像馏谨,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子附迷,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,828評論 2 345

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