依賴注入容器理解

Dependency Injection Container (依賴注入容器)
首先,它是一個容器,里面裝的是依賴,而依賴則是一個個你需要使用的服務,具體來說就是一個個對象。

耦合

一個好的代碼結構設計一定是松耦合的,這也是很多通用設計模式的宗旨,就是把分散在各處的同一個功能的代碼匯聚到一起,形成一個模塊,然后在不同模塊之間通過一些細小的、明確的渠道進行溝通。

在實踐中,不同功能和模塊之間的互相依賴是不可避免的,而如何處理好這些依賴之間的關系則是代碼結構能否變得美好的關鍵。

一個例子??:

<?php
class User
{
    public function register($user)
    {
        // 注冊操作
        ...

        // 發送確認郵件
        $notify = new Notify();
        $notify->sendEmail('register', $user);
    }
}

class Notify
{
    public function sendEmail($type, $data)
    {
        switch $type {
            case 'register':
                // 發送注冊確認郵件
                $email = new Email($type);
                $email->send($data);
            ...
        }
    }
}

class Email
{
    public function send($data)
    {
        // 發送郵件
    }
}

上述代碼中,三個類之間逐層依賴,三個類實例化的順序是 User -> Notify -> Email,也就是說我先實例化User類,可能執行了一些代碼之后再去實例化我需要的其他類,比如Notify,以此類推。這種依賴會讓我們不得不為了得到需要的依賴而去做的一些準備工作,有時候可能一個new操作還不夠。而這部分工作就是所說的耦合,他會讓一個獨立功能的類不得不去關心一些和自己的主體功能沒什么關系的操作。

解除一個類對其他類的依賴

要解決這個問題也很簡單,我可以先實例化好Email類,然后再實例化Notify,然后把Email對象作為參數傳給Notify,最后實例化User類,然后把Notify傳進去。這就是所謂的依賴注入,可以看到這個過程中類實例化的順序完全反過來了,先實例化被依賴的對象,而不是先實例化最終需要的對象,這是控制反轉

代碼如下:

<?php
$email = new Email();
$notify = new Notify($email);
$user = new User($notify);

可以通過構造函數來注入需要的依賴,也可以用一些其他的方法。

用容器托管依賴

那又有新的問題,例子中只有三個類還好,那如果這個User類依賴Notify來發郵件,依賴Model來存數據庫,依賴redis來緩存,這樣固然把依賴關系轉移到了類的外部,但還是會導致我只想實例化一下User的時候,卻要手動做很多的準備工作,會讓代碼混亂。所以這個時候需要一個容器。而這個容器的作用就是替我來管理這些依賴。

<?php
// 容器
class Container implements ArrayAccess
{
    protected $values = [];

    public function offsetGet($offset) 
    {
        return $this->values[$offset]($this);
    }

    public function offsetSet($offset, $value) 
    {
        $this->values[$offset] = $value;
    }
}

在程序啟動的時候,我們可以在一個地方統一的注冊好一系列的基礎服務。

<?php
$container = new Container();

$container['notify'] = function($c) {
    return new Notify();
};

$container['email'] = function($c) {
    return new Email();
};

就會變成這樣

<?php
class User
{
    public function register($user)
    {
        // 注冊操作
        ...

        // 發送確認郵件
        $container('notify')->sendEmail('register', $user);
    }
}

class Notify
{
    public function sendEmail($type, $data)
    {
        switch $type {
            case 'register':
                // 發送注冊確認郵件
                $email = $container['email'];
                $email->send($data);
            ...
        }
    }
}

class Email
{
    public function send($data)
    {
        // 發送郵件
    }
}

就是當User需要Notify的時候,會去向容器要這個類的對象,那至于Notify再依賴什么其他的東西,我就不用管了,因為Notify也會去向容器要它自己需要的依賴。所有這些依賴關系的處理就完全托管給容器了,我們既不需要去關心依賴之間的層次關系,也避免了依賴之間的耦合。

需要注意的是,依賴注入容器一般只接受一個匿名函數,而不是一個實例化好的對象,匿名函數會告訴容器怎樣去獲得一個對象,這樣可以使得一個服務在被需要的時候才會去實例化,

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,758評論 18 399
  • 設計模式概述 在學習面向對象七大設計原則時需要注意以下幾點:a) 高內聚、低耦合和單一職能的“沖突”實際上,這兩者...
    彥幀閱讀 3,776評論 0 14
  • 如果你沒有做今天這件事情,你就永遠不會知道,給自己一些壓力之后,你能夠做到些什么。一個人覺得最引以為自豪的事情,往...
    向天再借五百瓶閱讀 277評論 0 1
  • 今天在微信里看了一篇介紹木心先生的文章,讓我對木心先生的了解更進一步。知道木心這個名字,還是看了陳丹青的紀錄片局部...
    xinrulianhua閱讀 741評論 0 0
  • 這本書是軍機處的一位朋友推薦給我的,乍一聽,心中就歡喜“徒然”二字,讓人產生“無聊”“無用”“百無聊賴”的聯想,找...
    ichbin夢夢閱讀 346評論 1 0