您好,登錄后才能下訂單哦!
這篇文章是關(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
免責(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)容。