《依賴注入 初相見》

不詩意的女程序媛不是好廚師~
轉(zhuǎn)載請(qǐng)注明出處,F(xiàn)rom李詩雨---https://blog.csdn.net/cjm2484836553/article/details/104449190

在這里插入圖片描述

上篇我們學(xué)習(xí)了注解的基本知識(shí)库继,今天我們?cè)賮韺W(xué)習(xí)一下依賴注入。

當(dāng)讓我們也不是一下子就來說依賴注入,而是秉著循序漸進(jìn)的原則蒋搜,一點(diǎn)一點(diǎn)的理解册着。

那就讓我們開始吧~

1.什么是依賴(Dependency)?

通俗點(diǎn)來講 依賴 就是一種需要逃顶。

依賴是類與類之間的連接讨便,依賴關(guān)系表示一個(gè)類依賴于另一個(gè)類的定義。

【舉個(gè)栗子】:

例如一個(gè)人(Person)可以買車(Car)和房子(House),那Person類就依賴于Car類和House類以政。

public static void main(String[] args) {
    Person person = new Person();
    person.buy(new House());
    person.buy(new Car());
}

static class Person {
    //表示依賴House
    public void buy(House house) {
        System.out.println("買了套房");
    }

    //表示依賴Car
    public void buy(Car car) {
        System.out.println("買了輛車");
    }
}

static class House {
}

static class Car {
}

嗯吶霸褒,了解了依賴是什么,接下來繼續(xù)下一個(gè)概念:依賴倒置 ~

2.什么是 依賴倒置 盈蛮?

2.0 順序依賴

有時(shí)候理解一個(gè)東西废菱,通過反面來理解也不失為一種好的方法。

那依賴倒置的反面就是不依賴倒置了抖誉,就是順序依賴了昙啄。

什么是順序依賴呢?

比如說:


在這里插入圖片描述

人的出行依賴于車子寸五,那如果出行由自行車變成了汽車梳凛,人對(duì)應(yīng)的類就要改變;如果又變成了火車梳杏,人對(duì)應(yīng)的類又要改變韧拒。

人依賴于車子,車子一變十性,人就要跟著改變叛溢,這種就叫順序的依賴。

public class Person {
    private Bike mBike;
    private Car mCar;
    private Train mTrain;

    public Person() {
        mBike = new Bike();
        //mCar = new Car();// ①變---改為汽車
        //mTrain = new Train();//②變---改為火車
    }

    public void goOut() {
        System.out.println("依賴于車子要出門了~");
        mBike.drive();
        //mCar.drive();  //①跟著變
        //mTrain.drive();  //②跟著變
    }

    public static void main(String... args) {
        Person person = new Person();
        person.goOut();
    }
}

好的劲适,了解了順序的依賴楷掉,那依賴的倒置就是反過來嘍,那就讓我再來繼續(xù)看看吧~

2.1依賴倒置的定義

依賴倒置是面向?qū)ο笤O(shè)計(jì)領(lǐng)域的一種軟件設(shè)計(jì)原則霞势。

依賴倒置原則(Dependence Inversion Principle,簡(jiǎn)稱DIP)

  • 核心思想:高層模塊不應(yīng)該依賴底層模塊烹植,二者都該依賴其抽象斑鸦;抽象不應(yīng)該依賴細(xì)節(jié);細(xì)節(jié)應(yīng)該依賴抽象草雕;
  • 說明:高層模塊就是調(diào)用端巷屿,低層模塊就是具體實(shí)現(xiàn)類。抽象就是指接口或抽象類墩虹。細(xì)節(jié)就是實(shí)現(xiàn)類嘱巾。
  • 通俗來講: 依賴倒置原則的本質(zhì)就是通過抽象(接口或抽象類)使個(gè)各類或模塊的實(shí)現(xiàn)彼此獨(dú)立,互不影響诫钓,實(shí)現(xiàn)模塊間的松耦合旬昭。
  • 問題描述: 類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修改為依賴接口interface驰唬,類B和類C各自實(shí)現(xiàn)接口interface,類A通過接口interface間接與類B或者類C發(fā)生聯(lián)系腔彰,則會(huì)大大降低修改類A的幾率叫编。
  • 好處:依賴倒置的好處在小型項(xiàng)目中很難體現(xiàn)出來。但在大中型項(xiàng)目中可以減少需求變化引起的工作量霹抛。使并行開發(fā)更友好搓逾。

我們現(xiàn)在知道了依賴倒置原則的核心是:

  1. 上層模塊不應(yīng)該依賴底層模塊,它們都應(yīng)該依賴于抽象杯拐。
  2. 抽象不應(yīng)該依賴于細(xì)節(jié)霞篡,細(xì)節(jié)應(yīng)該依賴于抽象。

那什么是上層模塊和底層模塊 端逼,什么又是抽象和細(xì)節(jié)呢朗兵?

我們來繼續(xù)往下看~

2.2上層模塊和底層模塊

就拿一個(gè)公司來說吧,它一定有架構(gòu)的設(shè)計(jì)顶滩、有職能的劃分余掖。按照職能的重要性,自然而然就有了上下之分礁鲁。并且盐欺,隨著模塊的粒度劃分不同這種上層與底層模塊會(huì)進(jìn)行變動(dòng)赁豆,也許某一模塊相對(duì)于另外一模塊它是底層,但是相對(duì)于其他模塊它又可能是上層找田。


在這里插入圖片描述

如圖歌憨,公司管理層就是上層,CEO 是整個(gè)事業(yè)群的上層墩衙,那么 CEO 職能之下就是底層务嫡。

然后,我們?cè)僖允聵I(yè)群為整個(gè)體系劃分模塊漆改,各個(gè)部門經(jīng)理以上部分是上層心铃,那么之下的組織都可以稱為底層。

由此挫剑,我們可以看到去扣,在一個(gè)特定體系中,上層模塊與底層模塊可以按照決策能力高低為準(zhǔn)繩進(jìn)行劃分樊破。

那么愉棱,映射到我們軟件實(shí)際開發(fā)中,一般我們也會(huì)將軟件進(jìn)行模塊劃分哲戚,比如業(yè)務(wù)層奔滑、邏輯層和數(shù)據(jù)層。


在這里插入圖片描述

業(yè)務(wù)層中是軟件真正要進(jìn)行的操作顺少,也就是做什么朋其。
邏輯層是軟件現(xiàn)階段為了業(yè)務(wù)層的需求提供的實(shí)現(xiàn)細(xì)節(jié),也就是怎么做脆炎。
數(shù)據(jù)層指業(yè)務(wù)層和邏輯層所需要的數(shù)據(jù)模型梅猿。

因此,如前面所總結(jié)秒裕,按照決策能力的高低進(jìn)行模塊劃分袱蚓。業(yè)務(wù)層自然就處于上層模塊,邏輯層和數(shù)據(jù)層自然就歸類為底層几蜻。

2.3抽象和具體

抽象如其名字一樣癞松,是一件很抽象的事物。

抽象往往是相對(duì)于具體而言的入蛆,具體也可以被稱為細(xì)節(jié)响蓉。

比如:

1.交通工具是抽象,而公交車哨毁、單車枫甲、火車等就是具體了。

2.表演是抽象,而唱歌想幻、跳舞粱栖、小品等就是具體。

由此可見脏毯,抽象可以是物也可以是行為闹究。

在我們實(shí)際的軟件開發(fā)中,抽象有兩種形式:接口 & 抽象類食店。

/**
 * Driveable 是接口渣淤,所以它是抽象
 */
public interface Driveable {
    void drive();
}
/**
 * 而 Bike 實(shí)現(xiàn)了接口,它被稱為具體吉嫩。
 */
public class Bike implements Driveable {
    @Override
    public void drive() {
        System.out.println("Bike drive");
    }
}

2.4依賴倒置的好處

在上述的人與車子的例子中价认,只要車子的類型一變,Person類就要跟著改動(dòng)自娩。

那有沒有一種方法能讓 Person 的變動(dòng)少一點(diǎn)呢用踩?

因?yàn)楫吘刮覀儗懙氖亲罨A(chǔ)的演示代碼,如果工程大了忙迁,代碼復(fù)雜了脐彩,Person 面對(duì)需求變動(dòng)時(shí)改動(dòng)的地方會(huì)更多。

而依賴倒置原則正好適用于解決這類情況姊扔。

下面惠奸,我們嘗試運(yùn)用依賴倒置原則對(duì)代碼進(jìn)行改造。

我們?cè)俅位仡櫹滤亩x旱眯。

上層模塊不應(yīng)該依賴底層模塊晨川,它們都應(yīng)該依賴于抽象证九。

抽象不應(yīng)該依賴于細(xì)節(jié)删豺,細(xì)節(jié)應(yīng)該依賴于抽象。

首先是上層模塊和底層模塊的拆分愧怜。

按照決策能力高低或者重要性劃分呀页,Person 屬于上層模塊,Bike拥坛、Car 和 Train 屬于底層模塊蓬蝶。

上層模塊不應(yīng)該依賴于底層模塊。


在這里插入圖片描述
public class Person {
    //======順序的依賴======
    //private Bike mBike;
    //private Car mCar;
    //private Train mTrain;

    //=====依賴倒置=====
    private Driveable mDriveable;

    public Person() {
        //======順序的依賴======
        //mBike = new Bike();
        //mCar = new Car();// ①變---改為汽車
        //mTrain = new Train();//②變---改為火車

        //=====依賴倒置=====
        mDriveable = new Train(); //依賴倒置猜惋,只需要改這里就可以了丸氛,其他地方不用修改了

    }

    public void goOut() {
        System.out.println("依賴于車子要出門了~");
        //======順序的依賴======
        //mBike.drive();
        //mCar.drive();  //①跟著變
        //mTrain.drive();  //②跟著變

        //=====依賴倒置=====
        mDriveable.drive();
    }

    public static void main(String... args) {
        Person person = new Person();
        person.goOut();
    }
}

可以看到,依賴倒置實(shí)質(zhì)上是面向接口編程的體現(xiàn)著摔。

好的缓窜,通過上面的講解相信你已經(jīng)漸漸體會(huì)到什么是依賴倒置了。

但是,在編碼的過程中禾锤,我們還是發(fā)現(xiàn)它的一個(gè)不足私股,那就是它不符合開閉原則。

每次我們都要修改Person類的內(nèi)部恩掷,那我們能不能再不修改Person類內(nèi)部的情況下倡鲸,來實(shí)現(xiàn)同樣的功能呢?

答案當(dāng)時(shí)是肯定的黄娘,所以接下來我們?cè)賮韺W(xué)習(xí)一下 控制反轉(zhuǎn)峭状。

3.什么是控制反轉(zhuǎn)?

控制反轉(zhuǎn)( IoC )是 Inversion of Control的縮寫寸宏,意思就是對(duì)于控制權(quán)的反轉(zhuǎn)宁炫。

上面的實(shí)例中,Person自己掌控著內(nèi)部 mDriveable 的實(shí)例化氮凝。

現(xiàn)在羔巢,我們可以更改一種方式。將 mDriveable 的實(shí)例化移到 Person 外面罩阵。

public class Person2 {
    private Driveable mDriveable;

    public Person2(Driveable driveable) {
        this.mDriveable = driveable;
    }

    public void goOut() {
        System.out.println("出門啦");
        mDriveable.drive();
    }

    public static void main(String... args) {
        Person2 person = new Person2(new Car());//變?yōu)榱嗽赑erson的外部進(jìn)行改變
        person.goOut();
    }
}

就這樣無論出行方式怎么變化竿秆,Person 這個(gè)類都不需要更改代碼了。

在上面代碼中稿壁,Person 把內(nèi)部依賴的創(chuàng)建權(quán)力移交給了 Person2這個(gè)類中的 main() 方法幽钢。也就是說 Person 只關(guān)心依賴提供的功能,但并不關(guān)心依賴的創(chuàng)建傅是。

這種思想其實(shí)就是 IoC匪燕,IoC 是一種新的設(shè)計(jì)模式,它對(duì)上層模塊與底層模塊進(jìn)行了更進(jìn)一步的解耦喧笔。控制反轉(zhuǎn)的意思是反轉(zhuǎn)了上層模塊對(duì)于底層模塊的依賴控制帽驯。

好了,學(xué)習(xí)了這么多的概念书闸,現(xiàn)在我們終于有了一定的基礎(chǔ)來學(xué)習(xí)依賴注入了~

4.什么是依賴注入

依賴注入尼变,也經(jīng)常被簡(jiǎn)稱為 DI,其實(shí)在上一節(jié)中浆劲,我們已經(jīng)見到了它的身影嫌术。它是一種實(shí)現(xiàn) IoC 的手段。什么意思呢牌借?

為了不因?yàn)橐蕾噷?shí)現(xiàn)的變動(dòng)而去修改 Person度气,也就是說以可能在 Driveable 實(shí)現(xiàn)類的改變下不改動(dòng) Person 這個(gè)類的代碼,盡可能減少兩者之間的耦合膨报。我們需要采用上一節(jié)介紹的 IoC 模式來進(jìn)行改寫代碼磷籍。

這個(gè)需要我們移交出對(duì)于依賴實(shí)例化的控制權(quán)哲虾,那么依賴怎么辦?Person 無法實(shí)例化依賴了择示,它就需要在外部(IoC 容器)賦值給它束凑,這個(gè)賦值的動(dòng)作有個(gè)專門的術(shù)語叫做注入(injection),需要注意的是在 IoC 概念中栅盲,這個(gè)注入依賴的地方被稱為 IoC 容器汪诉,但在依賴注入概念中,一般被稱為注射器 (injector)谈秫。

表達(dá)通俗一點(diǎn)就是:我不想自己實(shí)例化依賴扒寄,你(injector)創(chuàng)建它們,然后在合適的時(shí)候注入給我拟烫。

實(shí)現(xiàn)依賴注入有 3 種方式:

  1. 構(gòu)造函數(shù)中注入
  2. setter 方式注入
  3. 接口注入
/**
 * 接口方式注入
 * 接口的存在该编,表明了一種依賴配置的能力。
 */
public interface DepedencySetter {
    void set(Driveable driveable);
}
public class Person2 implements DepedencySetter {
    //接口方式注入
    @Override
    public void set(Driveable driveable) {
        this.mDriveable = mDriveable;
    }

    private Driveable mDriveable;

    //構(gòu)造函數(shù)注入
    public Person2(Driveable driveable) {
        this.mDriveable = driveable;
    }

    //setter 方式注入
    public void setDriveable(Driveable mDriveable) {
        this.mDriveable = mDriveable;
    }

    public void goOut() {
        System.out.println("出門啦");
        mDriveable.drive();
    }

    public static void main(String... args) {
        Person2 person = new Person2(new Car());
        person.goOut();
    }
}

所以硕淑,依賴注入大家要記住的重點(diǎn)就是 : 依賴注入是實(shí)現(xiàn)控制反轉(zhuǎn)的手段课竣。

積累點(diǎn)滴,做好自己~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末置媳,一起剝皮案震驚了整個(gè)濱河市于樟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌拇囊,老刑警劉巖迂曲,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異寥袭,居然都是意外死亡路捧,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門传黄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來杰扫,“玉大人,你說我怎么就攤上這事尝江∩娌ǎ” “怎么了英上?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵炭序,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我苍日,道長(zhǎng)惭聂,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任相恃,我火速辦了婚禮辜纲,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己耕腾,他們只是感情好见剩,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著扫俺,像睡著了一般苍苞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上狼纬,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天羹呵,我揣著相機(jī)與錄音,去河邊找鬼疗琉。 笑死冈欢,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的盈简。 我是一名探鬼主播凑耻,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼柠贤!你這毒婦竟也來了拳话?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤种吸,失蹤者是張志新(化名)和其女友劉穎弃衍,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坚俗,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡镜盯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了猖败。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片速缆。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖恩闻,靈堂內(nèi)的尸體忽然破棺而出艺糜,到底是詐尸還是另有隱情,我是刑警寧澤幢尚,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布哈扮,位于F島的核電站次慢,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜护姆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一杜恰、第九天 我趴在偏房一處隱蔽的房頂上張望竹宋。 院中可真熱鬧,春花似錦管嬉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至烛占,卻和暖如春求厕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背扰楼。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工呀癣, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人弦赖。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓项栏,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蹬竖。 傳聞我的和親對(duì)象是個(gè)殘疾皇子沼沈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

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