對(duì)依賴注入和控制反轉(zhuǎn)的一點(diǎn)理解

1.1、IoC是什么

Ioc—Inversion of Control,即“控制反轉(zhuǎn)”欣喧,不是什么技術(shù),而是一種設(shè)計(jì)思想梯找。在Java開發(fā)中唆阿,Ioc意味著將你設(shè)計(jì)好的對(duì)象交給容器控制,而不是傳統(tǒng)的在你的對(duì)象內(nèi)部直接控制锈锤。如何理解好Ioc呢驯鳖?理解好Ioc的關(guān)鍵是要明確“誰控制誰闲询,控制什么,為何是反轉(zhuǎn)(有反轉(zhuǎn)就應(yīng)該有正轉(zhuǎn)了)浅辙,哪些方面反轉(zhuǎn)了”扭弧,那我們來深入分析一下:
  ●誰控制誰,控制什么:傳統(tǒng)Java SE程序設(shè)計(jì)记舆,我們直接在對(duì)象內(nèi)部通過new進(jìn)行創(chuàng)建對(duì)象鸽捻,是程序主動(dòng)去創(chuàng)建依賴對(duì)象;而IoC是有專門一個(gè)容器來創(chuàng)建這些對(duì)象泽腮,即由Ioc容器來控制對(duì) 象的創(chuàng)建御蒲;誰控制誰?當(dāng)然是IoC 容器控制了對(duì)象诊赊;控制什么厚满?那就是主要控制了外部資源獲取(不只是對(duì)象包括比如文件等)碧磅。
  ●為何是反轉(zhuǎn)痰滋,哪些方面反轉(zhuǎn)了:有反轉(zhuǎn)就有正轉(zhuǎn),傳統(tǒng)應(yīng)用程序是由我們自己在對(duì)象中主動(dòng)控制去直接獲取依賴對(duì)象续崖,也就是正轉(zhuǎn);而反轉(zhuǎn)則是由容器來幫忙創(chuàng)建及注入依賴對(duì)象团搞;為何是反轉(zhuǎn)严望?因?yàn)橛扇萜鲙臀覀儾檎壹白⑷胍蕾噷?duì)象,對(duì)象只是被動(dòng)的接受依賴對(duì)象逻恐,所以是反轉(zhuǎn)像吻;哪些方面反轉(zhuǎn)了?依賴對(duì)象的獲取被反轉(zhuǎn)了复隆。

1.2拨匆、IoC能做什么

IoC 不是一種技術(shù),只是一種思想挽拂,一個(gè)重要的面向?qū)ο缶幊痰姆▌t惭每,它能指導(dǎo)我們?nèi)绾卧O(shè)計(jì)出松耦合、更優(yōu)良的程序亏栈。傳統(tǒng)應(yīng)用程序都是由我們?cè)陬悆?nèi)部主動(dòng)創(chuàng)建依賴對(duì)象台腥,從而導(dǎo)致類與類之間高耦合,難于測(cè)試绒北;有了IoC容器后黎侈,把創(chuàng)建和查找依賴對(duì)象的控制權(quán)交給了容器,由容器進(jìn)行注入組合對(duì)象闷游,所以對(duì)象與對(duì)象之間是 松散耦合峻汉,這樣也方便測(cè)試贴汪,利于功能復(fù)用,更重要的是使得程序的整個(gè)體系結(jié)構(gòu)變得非常靈活休吠。
  其實(shí)IoC對(duì)編程帶來的最大改變不是從代碼上扳埂,而是從思想上,發(fā)生了“主從換位”的變化蛛碌。應(yīng)用程序原本是老大聂喇,要獲取什么資源都是主動(dòng)出擊,但是在IoC/DI思想中蔚携,應(yīng)用程序就變成被動(dòng)的了希太,被動(dòng)的等待IoC容器來創(chuàng)建并注入它所需要的資源了。
  IoC很好的體現(xiàn)了面向?qū)ο笤O(shè)計(jì)法則之一—— 好萊塢法則:“別找我們酝蜒,我們找你”誊辉;即由IoC容器幫對(duì)象找相應(yīng)的依賴對(duì)象并注入,而不是由對(duì)象主動(dòng)去找亡脑。

1.3堕澄、IoC和DI

DI—Dependency Injection,即“依賴注入”:組件之間依賴關(guān)系由容器在運(yùn)行期決定霉咨,形象的說蛙紫,即由容器動(dòng)態(tài)的將某個(gè)依賴關(guān)系注入到組件之中。依賴注入的目的并非為軟件系統(tǒng)帶來更多功能途戒,而是為了提升組件重用的頻率坑傅,并為系統(tǒng)搭建一個(gè)靈活喷斋、可擴(kuò)展的平臺(tái)浆西。通過依賴注入機(jī)制顽腾,我們只需要通過簡(jiǎn)單的配置抄肖,而無需任何代碼就可指定目標(biāo)需要的資源憎瘸,完成自身的業(yè)務(wù)邏輯,而不需要關(guān)心具體的資源來自何處潮售,由誰實(shí)現(xiàn)酥诽。
  理解DI的關(guān)鍵是:“誰依賴誰,為什么需要依賴咖驮,誰注入誰训枢,注入了什么”睦刃,那我們來深入分析一下:
  ●誰依賴于誰:當(dāng)然是應(yīng)用程序依賴于IoC容器十酣;
  ●為什么需要依賴:應(yīng)用程序需要IoC容器來提供對(duì)象需要的外部資源兴泥;
  ●誰注入誰:很明顯是IoC容器注入應(yīng)用程序某個(gè)對(duì)象虾宇,應(yīng)用程序依賴的對(duì)象文留;
  ●注入了什么:就是注入某個(gè)對(duì)象所需要的外部資源(包括對(duì)象燥翅、資源森书、常量數(shù)據(jù))凛膏。
  IoC和DI由什么關(guān)系呢脏榆?其實(shí)它們是同一個(gè)概念的不同角度描述须喂,由于控制反轉(zhuǎn)概念比較含糊(可能只是理解為容器控制對(duì)象這一個(gè)層面,很難讓人想到誰來維護(hù)對(duì)象關(guān)系)掷伙,所以2004年大師級(jí)人物Martin Fowler又給出了一個(gè)新的名字:“依賴注入”,相對(duì)IoC 而言沛厨,“依賴注入”明確描述了“被注入對(duì)象依賴IoC容器配置依賴對(duì)象”绸栅。
  看過很多對(duì)Spring的Ioc理解的文章粹胯,好多人對(duì)Ioc和DI的解釋都晦澀難懂风纠,反正就是一種說不清竹观,道不明的感覺臭增,讀完之后依然是一頭霧水誊抛,感覺就是開濤這位技術(shù)牛人寫得特別通俗易懂拗窃,他清楚地解釋了IoC(控制反轉(zhuǎn)) 和DI(依賴注入)中的每一個(gè)字随夸,讀完之后給人一種豁然開朗的感覺。我相信對(duì)于初學(xué)Spring框架的人對(duì)Ioc的理解應(yīng)該是有很大幫助的伍俘。

用php例子來解釋控制反轉(zhuǎn)和依賴注入

先看一個(gè)例子:

<?php
class A
{
    public $b;
    public $c;
    public function A()
    {
        //TODO
    }
    public function Method()
    {
        $this->b=new B();
        $this->c=new C();
   
        $this->b->Method();
        $this->c->Method();
         
        //TODO
    }
}
 
class B
{
    public function B()
    {
        //TODO
    }
    public function Method()
    {
        //TODO
        echo 'b';
    }
}
 
class C
{
    public function C()
    {
        //TODO
    }
    public function Method()
    {
        //TODO
        echo 'c';
    }
}
 
$a=new A();
$a->Method();
?>

上面代碼,我們很容易理解一句話:

A類依賴B類和C類

也就是說妇萄,如果今后開發(fā)過程中咬荷,要對(duì)B類或者C類修改冠句,一旦涉及函數(shù)改名,函數(shù)參數(shù)數(shù)量變動(dòng)幸乒,甚至整個(gè)類結(jié)構(gòu)的調(diào)整懦底,我們也要對(duì)A類做出相應(yīng)的調(diào)整,A類的獨(dú)立性喪失了罕扎,這在開發(fā)過程中是很不方便的聚唐,也就是我們說的“牽一發(fā)動(dòng)全身”,如果兩個(gè)類是兩個(gè)人分別寫的腔召,矛盾往往就在這個(gè)時(shí)候產(chǎn)生了杆查。。臀蛛。
萬一真的要改動(dòng)B類和C類亲桦,有沒有辦法,可以不去改動(dòng)或者盡量少改動(dòng)A類的代碼呢浊仆?這里要用到控制反轉(zhuǎn)客峭。

高層模塊不應(yīng)該依賴于底層模塊,兩個(gè)都應(yīng)該依賴抽象抡柿。

控制反轉(zhuǎn)(IOC)是一種思想舔琅,依賴注入(DI)是實(shí)施這種思想的方法。

第一種方法叫做:構(gòu)造器注入(這種方法也不推薦用沙绝,但比不用要好)

class A
{
    public $b;
    public $c;
    public function A($b,$c)
    {
        $this->b=$b;
        $this->c=$c;
    }
    public function Method()
    {
        $this->b->Method();
        $this->c->Method();
    }
}

客戶端類這樣寫:

$a=new A(new B(),new C());
$a->Method();

A類的構(gòu)造器依賴B類和C類,通過構(gòu)造器的參數(shù)傳入鼠锈,至少實(shí)現(xiàn)了一點(diǎn)闪檬,就是B類對(duì)象b和C類對(duì)象c的創(chuàng)建都移至了A類外,所以一旦B類和C類發(fā)生改動(dòng)购笆,A類無需做修改粗悯,只要在client類里改就可以了

假如有一天,我們需要擴(kuò)充B類同欠,做兩個(gè)B類的子類:

class B
{
    public function B()
    {
        //TODO
    }
    public function Method()
    {
        //TODO
        echo 'b';
    }
}
class B1 extends B
{
    public function B1()
    {
        //TODO
    }
    public function Method()
    {
        echo 'b1';
    }
}
class B2 extends B
{
    public function B2()
    {
        //TODO
    }
    public function Method()
    {
        echo 'b2';
    }
}

也很簡(jiǎn)單样傍,客戶端類這么寫:

$a=new A(new B2(),new C());
$a->Method();

所以A類是不用關(guān)心B類到底有哪些個(gè)子類的横缔,只要在客戶端類關(guān)心就可以了。

第二種方法叫做:工廠模式注入(推薦使用)

class Factory
{
    public function Factory()
    {
        //TODO
    }
    public function create($s)
    {
        switch($s)
        {
            case 'B':
            {
                return new B();
                break;
            }
            case 'C':
            {
                return new C();
                break;
            }
            default:
            {
                return null;
                break;
            }
        }
    }
}

我們A類代碼改為:

class A
{
    public $b;
    public $c;
    public function A()
    {
        //TODO
    }
    public function Method()
    {
        $f=new Factory();
        $this->b=$f->create('B');
        $this->c=$f->create('C');
         
        $this->b->Method();
        $this->c->Method();
         
        //TODO
    }
}

其實(shí)已經(jīng)解耦了一小部分衫哥,至少如果B類和C類的構(gòu)造函數(shù)要是發(fā)生變化茎刚,比如修改函數(shù)參數(shù)等,我們只需要改Factory類就可以了撤逢。
把B類和C類中的方法再抽象出來膛锭,做一個(gè)接口

interface IMethod
{
    public function Method();
}

這樣,A類中的b變量和c變量就不再是一個(gè)具體的變量了蚊荣,而是一個(gè)抽象類型的變量初狰,不到運(yùn)行那一刻,不知道他們的Method方式是怎么實(shí)現(xiàn)的互例。

class B implements IMethod
{
    public function B()
    {
        //TODO
    }
    public function Method()
    {
        //TODO
        echo 'b';
    }
}
 
class C implements IMethod
{
    public function C()
    {
        //TODO
    }
    public function Method()
    {
        //TODO
        echo 'c';
    }
}

總結(jié)幾點(diǎn):
1.我們把A類中的B類對(duì)象和C類對(duì)象的創(chuàng)建移至A類外
2.原本A類依賴B類和C類奢入,現(xiàn)在變成了A依賴Factory,F(xiàn)actory依賴B和C媳叨。

參考:
PHP控制反轉(zhuǎn)(IOC)和依賴注入(DI)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末腥光,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子肩杈,更是在濱河造成了極大的恐慌柴我,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扩然,死亡現(xiàn)場(chǎng)離奇詭異艘儒,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)夫偶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門界睁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人兵拢,你說我怎么就攤上這事翻斟。” “怎么了说铃?”我有些...
    開封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵访惜,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我腻扇,道長(zhǎng)债热,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任幼苛,我火速辦了婚禮窒篱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己墙杯,他們只是感情好配并,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著高镐,像睡著了一般溉旋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上避消,一...
    開封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天低滩,我揣著相機(jī)與錄音,去河邊找鬼岩喷。 笑死恕沫,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的纱意。 我是一名探鬼主播婶溯,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼偷霉!你這毒婦竟也來了迄委?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤类少,失蹤者是張志新(化名)和其女友劉穎叙身,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體硫狞,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡信轿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了残吩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片财忽。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖泣侮,靈堂內(nèi)的尸體忽然破棺而出即彪,到底是詐尸還是另有隱情,我是刑警寧澤活尊,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布隶校,位于F島的核電站,受9級(jí)特大地震影響蛹锰,放射性物質(zhì)發(fā)生泄漏深胳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一宁仔、第九天 我趴在偏房一處隱蔽的房頂上張望稠屠。 院中可真熱鬧峦睡,春花似錦翎苫、人聲如沸权埠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽攘蔽。三九已至,卻和暖如春呐粘,著一層夾襖步出監(jiān)牢的瞬間满俗,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工作岖, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留唆垃,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓痘儡,卻偏偏與公主長(zhǎng)得像辕万,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子沉删,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

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