您的位置 >>> 星想互聯 >>> 編程技術 >>> PHP高級編程
依賴注入(DI)和Ioc容器
點擊數:76  發布時間2020-06-06 20:55:26

Laravel這個框架,用起來方便,理解起來不簡單。

為什么不簡單?因為包含了一大堆所謂“先進”的概念,其中依賴注入(DI)和Ioc容器是比較核心的內容之一。

我百度了一下,講PHP DI和Ioc的內容很少,更別說詳解Laravel ioc的了。

在這里,我綜合了幾篇寫得比較典型的文章,以一個產品經理的身份,從用戶體驗的角度嘗試讓初學者也能比較容易理解這個2個概念。


DI和Ioc就是一種設計模式,這個概念已經存在10幾年了,請先對面向對象編程和設計模式(DesignPatterns)有初步的理解:

預先了解一下這三種模式:1. 工廠模式 2. 單例模式 3. 注冊器模式

也請了解一下 interface 的用法和作用;


如果上述內容你都不是很熟悉,沒關系,很簡單的,請接著看:


1. 首先來看 依賴注入(DI):

故事是這樣的:

我們知道寫一個類的時候,類本身是有個目的的,類里面有很多方法,每個方法搞定一些事情;


class Hookup {

 

public function getPhone(){

     //此處省略

}


public function inviteHer(){

     //此處省略

}


public function giveGifts(){

     //此處省略

}

public function kissHer(){

     //此處省略

}

}

比方說

這個類是什么意思?Hookup就是泡妞的意思,里面有4個步驟,第一步打電話,第二部邀請她共進晚餐,第三步送禮物,第四步打波兒,第五步.....我只能幫你到這里了...


別看只有4步,其實每一步都不簡單,第一步打電話,你得先要到人家電話吧,第二步邀請吃飯,你得提前訂好飯店吧,第三步送禮物,你得先買禮物吧~第四步Kiss,你總得抓住一個合適的機會吧;


當你在專心處理Hookup的時候,我太了解你了,你只關心結果,也就是抱得美人歸,問電話號碼,訂餐,買禮物,找機會這種小事,就交給其他“類”處理吧。


如下:

 require 'BuyGifts.php';



class Hookup {

 

public function getPhone(){

     //此處省略

}


public function inviteHer(){

     //此處省略

}


public function giveGifts(){

$gift = new BuyGifts();

$gift->select();

$gift->pay();

}

public function kissHer(){

     //此處省略

}

}


$paoniu = new hookup();

$paoniu->giveGifts();


這里面送禮物這個環節(比較懶,其他的不寫了),就引入了BuyGifts這個類,買禮物這種小事,就交給BuyGifts這個秘書去處理吧。


所以,一切問題的出發點,就是在一個類中調用其他類,我們要解決的,就是在這過程中會發生的問題。


Hookup這個可以稱之為主類,BuyGifts稱之為次類,為了實現主類的目標,要依賴很多次類來配合。


好,現在你已經知道什么是依賴了。


問題來了。現在講正經的。


比方說你很忙,你不僅要泡妞,還要開公司,做生意,沒事打打高爾夫球什么的。這每一件事都是一個“主類”,BuyGifts 這種“次類” ,除了泡妞,也可以放在 做生意這個類里面調用,做生意也要送禮的嘛,當然還可以應用在別的主類。 


如果BuyGifts被調用很多次,哪一天需要把名字改了,那你就必須在眾多主類中逐一修改。

還有就是,每一次調用都要new實例化一次。

這樣做不科學,你也知道。


怎么辦: 工廠模式

工廠模式很簡單,就是來幫助你批量實例化“次類”的。也就是說,用了工廠模式,你的主類中將不會再出現new這樣的關鍵字。


看實例,有3個類 哦:


-----   Factory.php    ----------


include 'BuyGifts.php'


class Factory {


static function getPhone(){

 

return new getPhone;

}



static function BuyGifts(){

 

return new BuyGifts;

}


//……下面還有很多,此處省略


}


-----   BuyGifts.php    ----------


class  BuyGifts{

 

public function select(){

//此處省略 }


public function pay(){

//此處省略 }


}


-----   Hookup.php    ----------


require 'BuyGifts.php';

require 'Factory.php ';


class Hookup {


private $gift;

 

public function getPhone(){

     //此處省略

}


public function inviteHer(){

     //此處省略

}


public function giveGifts(){

$this->gift = Factory::BuyGifts();

$gift->select();

$gift->pay();

}

public function kissHer(){

     //此處省略

}

}


$paoniu = new hookup();

$paoniu->giveGifts();



你看,現在主類Hookup 要調用次類BuyGifts,就得先去找Factory類,Factory就變成中介了。

Factory這個中介的主要服務就是幫 你實例化次類,另外管理很多次類(工廠嘛),這樣你就不用直接與次類發生關系。


這個過程就叫做 解耦,不管次類怎么變,你找工廠就可以了。


可是這樣做問題依舊存在,,當我們在很多主類里調用了工廠及其方法,可是有一天發現工廠類要改名,,或者工廠里面的方法要改名呢?那我們還不是得逐一改主類?雖然這種情況不多,但是這種不講信譽的“黑中介”也是偶爾會出現的。


怎么辦呢?我們對這個Factory 中介 也得 防 一手。


-----   Hookup.php    ----------


require 'BuyGifts.php';

require 'Factory.php ';


class Hookup {


private $gift;

 

public function getPhone(){

     //此處省略

}


public function inviteHer(){

     //此處省略

}


public function giveGifts(){

$gift->select();

$gift->pay();

}


public function kissHer(){

     //此處省略

}


public function setGift($instance){

$this->gift = $instance;

}

}


$paoniu = new hookup();

$paoniu->setGift(Factory::BuyGifts()); // 看到 Factory已經滾粗 我們的主類了

$paoniu->giveGifts();


現在Hookup類就像一個公司,作為老板的你只關心怎么泡妞,臟活累活交給別人干,于是你設立了一個setGift采購部門,這個部門專門負責和Factory中介打交道,這樣Factory中介就完全滾粗你的視野了。


Factory這個被依賴的對象 是通過參數 從外部 注入到 類內容的 靜態 屬性 實現實例化的,這個就是依賴注入。


可以聰明的你馬上發現,我擦,setGift 你這個部門就負責采購gift啊?我要打電話,發預約邀請難道還要setPhone,setInvitation嗎?


這樣主類里面要寫很多set方法,外面要調用很多次set方法,你會發現,更不科學了。

里面:

public function setGift($instance){

$this->gift = $instance;

}

public function setPhone($instance){

$this->phone = $instance;

}


public function setInvitation($instance){

$this->Invitation = $instance;

}


….


外面:


$paoniu->setGift(Factory::BuyGifts());

$paoniu->setPhone(Factory::GetPhone());

$paoniu->setInvitation(Factory::SendInvitation());


….



這個時候,你已經把Factory 趕出 Hookup公司了,所以,公司內部的事情,只能你自己搞定了。

公司外部的業務,這時Factory中介 又屁顛屁顛的跑過來找你,提出一個方案:


我們來搞個“總代”怎么樣?


class TopFactory {


public static function all_Agents_in_one(){

 

$paoniu_agent = new hookup();

          $paoniu_agent->setGift(Factory::BuyGifts()); 

$paoniu_agent->setPhone(Factory::GetPhone());

         $paoniu_agent->setInvitation(Factory::SendInvitation());

 

return $paoniu_agent;

}


}


黑中介Factory對你說:“你看我搞了個總代公司(TopFactory),你在外面也不要new啊,set什么的了,我全包了。


于是現在你在外面要做的變簡單了:


$paoniu = TopFactory::all_Agents_in_one();

$paoniu->giveGifts();//giveGifts里面就可以調用Buygifts了;

$paoniu->getPhone();

….



到現在為止,你已經有一套完整的 依賴注入方案了,這個方案組建的時候雖然有點復雜(層層轉包),但是一旦建好,維護起來比較方便。


可是,別忘了公司內部的事情還沒解決哪,另外要提醒你,你是程序員,不是老板,所以Factory那一部分也是你的活~~~



需要一種更高級的方案,讓程序員的生活變得Easier一些。

這個方案就是IoC容器,IoC容器首先是一種類注冊器,其次它是一種更高級的依賴注入方式。


它和工廠Factory其實性質一樣,都是中介代理,但實現機制不一樣。



工廠Factory 把 次類 一一對應 注冊到 類中的 實例化靜態方法中;

IoC容器是把 次類 實例化對象 依次 注冊到 類中一個靜態數組;



IoC容器的設計模式叫做 注冊器模式;


看實例:

———Di.php——-

class Di {

 

protected static $objects;


static function set($key, $object){


self::$objects[$key]=$object;


}


static function get ($key){


return self::$objects[$key];


}


static function unset ($key){


unset(self::$objects[$key]);


}



}



-----   Hookup.php    ----------


require ‘BuyGifts.php';

require 'Factory.php ';

require 'Di.php ';


class Hookup {


private $di;


function __construct(Di &$di){

       $this->_di = $di;

    }

 

public function getPhone(){

     //此處省略

}


public function inviteHer(){

     //此處省略

}


public function giveGifts(){

$this->di->get(‘BuyGifts’)->select();

$this->di->get(‘BuyGifts’)->pay();

}


public function kissHer(){

     //此處省略

}


public function setGift($instance){

$this->gift = $instance;

}

}


$di = new Di();

$di->set(‘BuyGift’, function(){

return Factory::BuyGift();

}



$paoniu=new Hookup($di);

$paoniu->giveGifts();



———-


可以看到,IoC模式才是真正的總代,它連公司內部的事情也管了。和設立set部門相比,set只能處理一個個單獨的業務,比如setGift,setPhone,setInvitation,之類的,,而ioc容器把這些實例全部放在一個數組里統一處理,并且還可以重新命名(鍵名),實現了完全的解耦。




請注意的是,我們在注冊Ioc容器的時候,是這樣寫的:

$di->set(‘BuyGift’, function(){

return Factory::BuyGift();

}


而沒有這樣寫:

$di->set(‘BuyGift’, Factory::BuyGift());



第一個參數是數組的鍵名,第二個參數是數組的值;


第一種寫法用了回調函數,它只有在讀取數組的值的時候才會被執行;

第二種方法直接實例化成一個對象,保存到數組的值中。第二種方法會比較占資源。

另外我們發現

$di = new Di();

$di->set(‘BuyGift’, function(){

return Factory::BuyGift();

}



$paoniu=new Hookup($di);

$paoniu->giveGifts();



這里面怎么還有new呢,我們用靜態方法和Factory寫得優雅一些:

Di::set(‘BuyGift’, function(){

return Factory::BuyGift();

} //注冊到容器

$paoniu=factory::Hookup(factory::DI()); // 將容器注入主類

$paoniu->giveGifts(); //這里就可以調用BuyGift()這個次類(依賴類);




好了,我們來看看Laravel Ioc容器 是怎么用的:


綁定類到容器


App::bind('foo', function()

{

    return newFooBar;

});


App 就是Ioc容器,bind就是set方法,’foo’ 就是數組中 實例的 鍵名;



至此,我們已經對Ioc容器有了一個比較清楚的認識,我們已經了解了工廠模式,注冊模式,依賴注入等知識,其實依賴注入有3種方式,,一種就是set注入(單類注入),一種是容器注入(Ioc),還有一種是接口注入(Interface);前兩種我們已經學習過了,后一種放在本文的第二部分來講。


在本文的第二部分,我們將詳細講解LaravelIoC的用法,為什么說Laravel理解起來比較難,因為它的設計不是入門級別的,而是專業級別的,比前面講的要復雜許多,但是看官方文檔,寥寥數語,真有種想砸電腦的沖動。

來源:咸寧網站建設
日本高清成 人,A级高清毛片av无码,欧美成 人 免费在线播放-首页 <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <文本链> <文本链> <文本链> <文本链> <文本链> <文本链>