溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

什么是依賴注入?

發(fā)布時(shí)間:2020-07-08 15:23:09 來(lái)源:網(wǎng)絡(luò) 閱讀:473 作者:v8v9v3000 欄目:web開發(fā)

這篇文章是關(guān)于一般依賴關(guān)系注入和在PHP中實(shí)現(xiàn)依賴注入容器系列的第一部分。

今天我不會(huì)談?wù)撊萜魅欢蚁胍砸恍┚唧w的示例介紹依賴注入的概念希望說(shuō)明嘗試去解決問(wèn)題和它給開發(fā)者帶來(lái)的好處。如果你已經(jīng)知道依賴注入的概念你可以略過(guò)本文等待下一篇。

依賴注入或許是我所知道的最簡(jiǎn)單的設(shè)計(jì)模式之一?;蛟S你已經(jīng)使用過(guò)依賴注入。但它是解釋最困難的一個(gè)。我認(rèn)為部分原因在于大多數(shù)介紹依賴注入的時(shí)候使用了沒(méi)有意義的示例。我試圖想出更符合PHP世界的例子由于PHP這種語(yǔ)言主要是用來(lái)做WEB開發(fā)的讓我們舉一個(gè)簡(jiǎn)單的WEB例子。

為了克服HTTP協(xié)議的無(wú)狀態(tài)性web應(yīng)用程序需要一種方法來(lái)存儲(chǔ)web請(qǐng)求之間的用戶信息。當(dāng)然通過(guò)使用一個(gè)cookie或者甚至更好的方式通過(guò)使用PHP內(nèi)置的會(huì)話機(jī)制(session)實(shí)現(xiàn)是非常簡(jiǎn)單的。

$_SESSION['language'] = 'fr';

上面的代碼中用語(yǔ)言會(huì)話變量存儲(chǔ)用戶的語(yǔ)言。因此針對(duì)同一個(gè)用戶的后續(xù)請(qǐng)求在超全局變量$_SESSION數(shù)組中的語(yǔ)言是有效的。

$user_language = $_SESSION['language'];

在面向?qū)ο蟮氖澜缰幸蕾囮P(guān)系注入才有意義讓我們假設(shè)我們有一個(gè)SessionStorage 類封裝了PHP的會(huì)話機(jī)制

class SessionStorage
{
    function __construct($cookieName = 'PHP_SESS_ID')
    {
        session_name($cookieName);
        session_start();
    }
    function set($key, $value)
    {
        $_SESSION[$key] = $value;
    }
    function get($key)
    {
        return $_SESSION[$key];
    }
    // ...
}

... 和一個(gè)提供了更高級(jí)別接口的用戶類

class User
{
    protected $storage;
    function __construct()
    {
        $this->storage = new SessionStorage();
    }
    function setLanguage($language)
    {
        $this->storage->set('language', $language);
    }
    function getLanguage()
    {
        return $this->storage->get('language');
    }
    // ...
}

這些類是足夠簡(jiǎn)單的使用User類相比更容易

$user = new User();
$user->setLanguage('fr');
$user_language = $user->getLanguage();

全部都很好...直到你想要更多的靈活性。如果你想要修改實(shí)例會(huì)話cookie的名稱下面是一些隨機(jī)的可能性

·User類里面是硬編碼的名稱在他的SessionStorage 構(gòu)造函數(shù)中:

class User
{
    function __construct()
    {
        $this->storage = new SessionStorage('SESSION_ID');
    }
    // ...
}

在User類的外面定義一個(gè)常量

class User
{
  function __construct()
  {
    $this->storage = new SessionStorage(STORAGE_SESSION_NAME);
  }
  // ...
}
define('STORAGE_SESSION_NAME', 'SESSION_ID');

添加會(huì)話的名稱session name作為User類的構(gòu)造函數(shù)的參數(shù)

class User
{
    function __construct($sessionName)
    {
        $this->storage = new SessionStorage($sessionName);
    }
                                                                                                                         
    // ...
}
$user = new User('SESSION_ID');

為存儲(chǔ)類SessionStorage添加一個(gè)選項(xiàng)數(shù)組

class User
{
    function __construct($storageOptions)
    {
        $this->storage = new SessionStorage($storageOptions['session_name']);
}
    // ...
}
$user = new User(array('session_name' => 'SESSION_ID'));

所有的這些選擇都是相當(dāng)糟糕的。在User類中的硬編碼會(huì)話名稱session name并沒(méi)有真正解決問(wèn)題你不能輕易改變想法以后而無(wú)需再次更改User類。使用一個(gè)常量之所以糟糕的因?yàn)?/span>User類現(xiàn)在依賴一個(gè)常量被設(shè)置。傳遞會(huì)話名稱session name作為一個(gè)參數(shù)或者作為一個(gè)選項(xiàng)數(shù)組是或許是最好的解決方法但它仍然很糟糕。用不相關(guān)的參數(shù)給對(duì)象本身打亂了User類構(gòu)造函數(shù)的參數(shù)。

但是仍然有問(wèn)題不能被解決我怎么才能更改SessionStorage 類呢例如為了方便測(cè)試將它替換為一個(gè)假對(duì)象?;蛘咭苍S是因?yàn)槟阆胍跀?shù)據(jù)庫(kù)表中或者內(nèi)存中存儲(chǔ)會(huì)話sessions。當(dāng)前實(shí)現(xiàn)是不可能的除非你修改User類。加入依賴注入而不是在User類里面建立SessionStorage 對(duì)象讓我們?cè)?/span>User對(duì)象通過(guò)傳遞一個(gè)構(gòu)造參數(shù)注入SessionStorage對(duì)象

class User
{
    function __construct($storage)
    {
        $this->storage = $storage;
    }
    // ...
}

這就是依賴注入。僅此而已使用User類現(xiàn)在多了一點(diǎn)包括你首先需要建立SessionStorage 對(duì)象

$storage = new SessionStorage('SESSION_ID');
$user = new User($storage);

現(xiàn)在配置會(huì)話存儲(chǔ)對(duì)象session storage object是非常簡(jiǎn)單的和替換會(huì)話存儲(chǔ)類也是非常容易。并且由于關(guān)注點(diǎn)的分離User類沒(méi)有改變一切都是可能的。

Pico Container website介紹的依賴注入就像這樣的

"Dependency Injection is where components are given their dependencies through their constructors, methods, or directly into fields."

“依賴注入是其中的組件通過(guò)他們的構(gòu)造器、方法、或者直接到字段的方式”給與他們的依賴關(guān)系。

至于其他的設(shè)計(jì)模式依賴注入也有一些反模式。Pico Container website介紹了其中的一些。

依賴注入不局限于構(gòu)造函數(shù)注入:

·構(gòu)造器注入:

class User
{
    function __construct($storage)
    {
        $this->storage = $storage;
    }
    // ...
}


·
Setter注入:

class User
{
    function setSessionStorage($storage)
    {
        $this->storage = $storage;
    }
    // ...
}


·
屬性注入:

class User
{
    public $sessionStorage;
}
$user->sessionStorage = $storage;


作為經(jīng)驗(yàn)法則構(gòu)造器所需要的依賴關(guān)系是最好的就像在我們的例子中
setter注入最適合可選的依賴關(guān)系比如像一個(gè)緩存實(shí)例對(duì)象。如今最現(xiàn)代化的PHP框架大量使用了依賴注入提供了一組解耦但內(nèi)聚的組件。

// symfony: A constructor injection example
$dispatcher = new sfEventDispatcher();
$storage = new sfMySQLSessionStorage(array('database' => 'session', 'db_table' => 'session'));
$user = new sfUser($dispatcher, $storage, array('default_culture' => 'en'));
// Zend Framework: A setter injection example
$transport = new Zend_Mail_Transport_Smtp('smtp.gmail.com', array(
    'auth'=> 'login',
    'username' => 'foo',
    'password' => 'bar',
    'ssl'=> 'ssl',
    'port'=> 465,
));
$mailer = new Zend_Mail();
$mailer->setDefaultTransport($transport);


如果你有興趣學(xué)習(xí)更多關(guān)于依賴注入我強(qiáng)烈建議你閱讀
Martin Fowler introduction或者優(yōu)秀的Jeff More presentation。你還可以去看看我去年給依賴注入做的介紹presentation在這篇文章中談?wù)摰脑诶锩嬷v了更多在例子上的細(xì)節(jié)。

今天就到這了。我希望你現(xiàn)在對(duì)依賴注入的概念有一個(gè)更好的理解。在本系列的下一篇文章我會(huì)談?wù)勔蕾囎⑷氲娜萜鳌?/span>


   原文地址http://fabien.potencier.org/article/11/what-is-dependency-injection



   

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI