




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、依賴注入與服務(wù)定位器(Dependency Injection/Service Location)¶接下來的例子有些長,但解釋了為什么我們使用依賴注入與服務(wù)定位器. 首先,假設(shè)我們正在開發(fā)一個組件,叫SomeComponent,它執(zhí)行的內(nèi)容現(xiàn)在還不重要。 我們的組件需要依賴數(shù)據(jù)庫的連接。在下面第一個例子中,數(shù)據(jù)庫的連接是在組件內(nèi)部建立的。這種方法是不實用的;事實上這樣做的話,我們不能改變創(chuàng)建數(shù)據(jù)庫連接的參數(shù)或者選擇不同的數(shù)據(jù)庫系統(tǒng),因為連接是當(dāng)組件被創(chuàng)建時建立的。<?phpclass SomeComponent /* * 連接數(shù)據(jù)庫的實例是被寫死在組件的內(nèi)部 * 因此,我們很難
2、從外部替換或者改變它的行為 */ public function someDbTask() $connection = new Connection(array( "host" => "localhost", "username" => "root", "password" => "secret", "dbname" => "invo" ); / . $some = new SomeComponent();$so
3、me->someDbTask();為了解決這樣的情況,我們建立一個setter,在使用前注入獨立外部依賴。現(xiàn)在,看起來似乎是一個不錯的解決辦法:<?phpclass SomeComponent protected $_connection; /* * 設(shè)置外部傳入的數(shù)據(jù)庫的連接實例 */ public function setConnection($connection) $this->_connection = $connection; public function someDbTask() $connection = $this->_connection; / .
4、 $some = new SomeComponent();/建立數(shù)據(jù)庫連接實例$connection = new Connection(array( "host" => "localhost", "username" => "root", "password" => "secret", "dbname" => "invo");/向組件注入數(shù)據(jù)連接實例$some->setConnection($connect
5、ion);$some->someDbTask();想一下,假設(shè)我們使用這個組件在應(yīng)用內(nèi)的好幾個地方都用到,然而我們在注入連接實例時還需要建立好幾次數(shù)據(jù)的連接實例。 如果我們可以獲取到數(shù)據(jù)庫的連接實例而不用每次都要創(chuàng)建新的連接實例,使用某種全局注冊表可以解決這樣的問題:<?phpclass Registry /* * 返回數(shù)據(jù)庫連接實例 */ public static function getConnection() return new Connection(array( "host" => "localhost", "us
6、ername" => "root", "password" => "secret", "dbname" => "invo" ); class SomeComponent protected $_connection; /* * 設(shè)置外部傳入的數(shù)據(jù)庫的連接實例 */ public function setConnection($connection) $this->_connection = $connection; public function someDbT
7、ask() $connection = $this->_connection; / . $some = new SomeComponent();/把注冊表中的連接實例傳遞給組件$some->setConnection(Registry:getConnection();$some->someDbTask();現(xiàn)在,讓我們設(shè)想一下,我們必須實現(xiàn)2個方法,第一個方法是總是創(chuàng)建一個新的連接,第二方法是總是使用一個共享連接:<?phpclass Registry protected static $_connection; /* * 建立一個新的連接實例 */ protected
8、 static function _createConnection() return new Connection(array( "host" => "localhost", "username" => "root", "password" => "secret", "dbname" => "invo" ); /* * 只建立一個連接實例,后面的請求只返回該連接實例 */ public static funct
9、ion getSharedConnection() if (self:$_connection=null) $connection = self:_createConnection(); self:$_connection = $connection; return self:$_connection; /* * 總是返回一個新的連接實例 */ public static function getNewConnection() return self:_createConnection(); class SomeComponent protected $_connection; /* * 設(shè)置
10、外部傳入的數(shù)據(jù)庫的連接實例 */ public function setConnection($connection) $this->_connection = $connection; /* * 這個方法總是需要共享連接實例 */ public function someDbTask() $connection = $this->_connection; / . /* * 這個方法總是需要新的連接實例 */ public function someOtherDbTask($connection) $some = new SomeComponent();/注入共享連接實例$some
11、->setConnection(Registry:getSharedConnection();$some->someDbTask();/這里我們總是傳遞一個新的連接實例$some->someOtherDbTask(Registry:getConnection();到目前為止,我們已經(jīng)看到依賴注入怎么解決我們的問題了。把依賴作為參數(shù)來傳遞,而不是建立在內(nèi)部建立它們,這使我們的應(yīng)用更加容易維護和更加解耦。不管怎么樣,長期來說,這種形式的依賴注入有一些缺點。例如,如果這個組件有很多依賴, 我們需要創(chuàng)建多個參數(shù)的setter方法來傳遞依賴關(guān)系,或者建立一個多個參數(shù)的構(gòu)造函數(shù)來傳遞它們
12、,另外在使用組件前還要每次都創(chuàng)建依賴,這讓我們的代碼像這樣不易維護:<?php/創(chuàng)建依賴實例或從注冊表中查找$connection = new Connection();$session = new Session();$fileSystem = new FileSystem();$filter = new Filter();$selector = new Selector();/把實例作為參數(shù)傳遞給構(gòu)造函數(shù)$some = new SomeComponent($connection, $session, $fileSystem, $filter, $selector);/ . 或者使用s
13、etter$some->setConnection($connection);$some->setSession($session);$some->setFileSystem($fileSystem);$some->setFilter($filter);$some->setSelector($selector);假設(shè)我們必須在應(yīng)用的不同地方使用和創(chuàng)建這些對象。如果當(dāng)你永遠不需要任何依賴實例時,你需要去刪掉構(gòu)造函數(shù)的參數(shù),或者去刪掉注入的setter。為了解決這樣的問題,我們再次回到全局注冊表創(chuàng)建組件。不管怎么樣,在創(chuàng)建對象之前,它增加了一個新的抽象層:<?p
14、hpclass SomeComponent / . /* * Define a factory method to create SomeComponent instances injecting its dependencies */ public static function factory() $connection = new Connection(); $session = new Session(); $fileSystem = new FileSystem(); $filter = new Filter(); $selector = new Selector(); return
15、 new self($connection, $session, $fileSystem, $filter, $selector); 瞬間,我們又回到剛剛開始的問題了,我們再次創(chuàng)建依賴實例在組件內(nèi)部!我們可以繼續(xù)前進,找出一個每次能奏效的方法去解決這個問題。但似乎一次又一次,我們又回到了不實用的例子中。一個實用和優(yōu)雅的解決方法,是為依賴實例提供一個容器。這個容器擔(dān)任全局的注冊表,就像我們剛才看到的那樣。使用依賴實例的容器作為一個橋梁來獲取依賴實例,使我們能夠降低我們的組件的復(fù)雜性:<?phpclass SomeComponent protected $_di; public functi
16、on _construct($di) $this->_di = $di; public function someDbTask() / 獲得數(shù)據(jù)庫連接實例 / 總是返回一個新的連接 $connection = $this->_di->get('db'); public function someOtherDbTask() / 獲得共享連接實例 / 每次請求都返回相同的連接實例 $connection = $this->_di->getShared('db'); / 這個方法也需要一個輸入過濾的依賴服務(wù) $filter = $this
17、->_di->get('filter'); $di = new PhalconDI();/在容器中注冊一個db服務(wù)$di->set('db', function() return new Connection(array( "host" => "localhost", "username" => "root", "password" => "secret", "dbname" =>
18、"invo" ););/在容器中注冊一個filter服務(wù)$di->set('filter', function() return new Filter(););/在容器中注冊一個session服務(wù)$di->set('session', function() return new Session(););/把傳遞服務(wù)的容器作為唯一參數(shù)傳遞給組件$some = new SomeComponent($di);$some->someTask();這個組件現(xiàn)在可以很簡單的獲取到它所需要的服務(wù),服務(wù)采用延遲加載的方式,只有在需要使用的時
19、候才初始化,這也節(jié)省了服務(wù)器資源。這個組件現(xiàn)在是高度解耦。例如,我們可以替換掉創(chuàng)建連接的方式,它們的行為或它們的任何其他方面,也不會影響該組件。實現(xiàn)方法(Our approach)¶PhalconDI 是一個實現(xiàn)依賴注入和定位服務(wù)的組件,而且它本身就是一個裝載它們的容器。因為Phalcon是高度解構(gòu)的,整合框架的不同組件,使用PhalconDI是必不可少的。開發(fā)者也可以使用這個組件去注入依賴和管理的應(yīng)用程序中來自不同類的全局實例。基本上,這個組件實現(xiàn)了 控制反轉(zhuǎn)(/wiki/%E6%8E%A7%E5%88%B6%E5%8F%8D%E8%BD
20、%AC) 的模式。使用這種模式,組件的對象不用再使用setter或者構(gòu)造函數(shù)去接受依賴實例,而是使用請求服務(wù)的依賴注入。這減少了總的復(fù)雜性,因為在組件內(nèi),只有一個方法去獲取所需的依賴實例。另外,該模式增加了代碼的可測試性,從而使其不易出錯。使用容器注冊服務(wù)(Registering services in the Container)¶框架本身或者開發(fā)者都可以注冊服務(wù)。當(dāng)一個組件A需要組件B(或者它的類的實例) 去操作,它可以通過容器去請求組件B,而不是創(chuàng)建一個新的組件B實例。這個工作方法給我們提供了許多優(yōu)勢:· 我們可以很容易的使用一個我們自己建立的或者是第三方的組件去替換
21、原有的組件。· 我們完全控制對象的初始化,這讓我們在傳遞它們的實例到組件之前,根據(jù)需要設(shè)置這些對象。· 我們可以在一個結(jié)構(gòu)化的和統(tǒng)一組件內(nèi)獲取全局實例。服務(wù)可以使用不同方式去定義:<?php/ 創(chuàng)建一個依賴注入容器$di = new PhalconDI();/ 通過類名稱設(shè)置服務(wù)$di->set("request", 'PhalconHttpRequest');/ 使用匿名函數(shù)去設(shè)置服務(wù),這個實例將被延遲加載$di->set("request", function() return new Phalc
22、onHttpRequest(););/ 直接注冊一個實例$di->set("request", new PhalconHttpRequest();/ 使用數(shù)組方式定義服務(wù)$di->set("request", array( "className" => 'PhalconHttpRequest');使用數(shù)組的方式去注冊服務(wù)也是可以的:<?php/ 創(chuàng)建一個依賴注入容器$di = new PhalconDI();/ 通過類名稱設(shè)置服務(wù)$di"request" = 'Pha
23、lconHttpRequest'/ 使用匿名函數(shù)去設(shè)置服務(wù),這個實例將被延遲加載$di"request" = function() return new PhalconHttpRequest();/ 直接注冊一個實例$di"request" = new PhalconHttpRequest();/ 使用數(shù)組方式定義服務(wù)$di"request" = array( "className" => 'PhalconHttpRequest');在上面的例子中,當(dāng)框架需要訪問request服務(wù)的內(nèi)
24、容,它會在容器里面查找名為request的服務(wù)。 在容器中將返回所需要的服務(wù)的實例。當(dāng)有需要時,開發(fā)者可能最終需要替換這個組件。每個方法(在上面的例子證明)用于設(shè)置/注冊服務(wù)方面具都具有優(yōu)勢和劣勢。這是由開發(fā)者和特別的要求決定具體使用哪個。通過字符串設(shè)置一個服務(wù)是很簡單,但是缺乏靈活性。通過數(shù)組設(shè)置服務(wù)提供了更加靈活的方式,但是使代碼更復(fù)雜。匿名函數(shù)是上述兩者之間的一個很好的平衡,但是會導(dǎo)致比預(yù)期的更多維護。PhalconDI 對每個儲存的服務(wù)提供了延遲加載。除非開發(fā)者選擇直接實例化一個對象并將其存儲在容器中,任何儲存在里面的對象(通過數(shù)組,字符串等等設(shè)置的)都將延遲加載,即只要當(dāng)使用到時才實
25、例化。簡單的注冊(Simple Registration)¶就像你之前看到的那樣,這里有幾種方法去注冊服務(wù)。下面是簡單調(diào)用的例子:字符串(String)¶使用字符串注冊服務(wù)需要一個有效的類名稱,它將返回指定的類對象,如果類還沒有加載的話,將使用自動加載器實例化對象。這種類型不允許向構(gòu)造函數(shù)指定參數(shù):<?php/ 返回 new PhalconHttpRequest(); 對象$di->set('request', 'PhalconHttpRequest');對象(Object)¶這種類型注冊服務(wù)需要一個對象。實際上,這個服
26、務(wù)不再需要初始化,因為它已經(jīng)是一個對象,可以說,這是不是一個真正的依賴注入,但是如果你想強制總是返回相同的對象/值,使用這種方式還是有用的:<?php/ 返回 PhalconHttpRequest(); 對象$di->set('request', new PhalconHttpRequest();閉包與匿名函數(shù)(Closures/Anonymous functions)¶這個方法提供了更加自由的方式去注冊依賴,但是如果你想從外部改變實例化的參數(shù)而不用改變注冊服務(wù)的代碼,這是很困難的:<?php$di->set("db", f
27、unction() return new PhalconDbAdapterPdoMysql(array( "host" => "localhost", "username" => "root", "password" => "secret", "dbname" => "blog" ););這些限制是可以克服的,通過傳遞額外的變量到閉包函數(shù)里面:<?php/ 把當(dāng)前域的$config變量傳遞給匿名函數(shù)使用$d
28、i->set("db", function() use ($config) return new PhalconDbAdapterPdoMysql(array( "host" => $config->host, "username" => $config->username, "password" => $config->password, "dbname" => $config->name ););復(fù)雜的注冊(Complex Registr
29、ation)¶如果要求不用實例化/解析服務(wù),就可以改變定義服務(wù)的話,我們需要使用數(shù)組的方式去定義服務(wù)。使用數(shù)組去定義服務(wù)可以更加詳細:<?php/ 通過類名和參數(shù),注冊logger服務(wù)$di->set('logger', array( 'className' => 'PhalconLoggerAdapterFile', 'arguments' => array( array( 'type' => 'parameter', 'value' =&g
30、t; './apps/logs/error.log' ) );/ 使用匿名函數(shù)的方式$di->set('logger', function() return new PhalconLoggerAdapterFile('./apps/logs/error.log'););上面兩種注冊服務(wù)的方式的結(jié)果是一樣的。然而,使用數(shù)組定義的話,在需要的時候可以變更注冊服務(wù)的參數(shù):<?php/ 改變logger服務(wù)的類名$di->getService('logger')->setClassName('MyCusto
31、mLogger');/ 不用實例化就可以改變第一個參數(shù)值$di->getService('logger')->setParameter(0, array( 'type' => 'parameter', 'value' => './apps/logs/error.log');除了使用數(shù)組的語法注冊服務(wù),你還可以使用以下三種類型的依賴注入:構(gòu)造函數(shù)注入(Constructor Injection)¶這個注入方式是通過傳遞依賴/參數(shù)到類的構(gòu)造函數(shù)。讓我們假設(shè)我們有下面的組件:<?phpnamespace SomeApp;use PhalconHttpResponse;class Some
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- GFRP筋-重晶石防輻射混凝土粘結(jié)性能試驗研究
- 關(guān)漢卿《救風(fēng)塵》的電視劇改編研究
- 創(chuàng)客大賽培訓(xùn)
- 兒童肺炎合并心衰補液診療要點
- 肺患者健康宣教
- 家庭科學(xué)教育實施策略
- 頤和園介紹課件
- 健康傳播常用方法
- 小班培訓(xùn)詐騙案例分享
- 預(yù)防要先行班會課件
- 化工公司安全知識競賽題庫(共1000題)
- 中國移動公開競聘考試題庫(含答案)
- DLT 572-2021 電力變壓器運行規(guī)程
- HJ 636-2012 水質(zhì) 總氮的測定 堿性過硫酸鉀消解紫外分光光度法
- 成都市2022級(2025屆)高中畢業(yè)班摸底測試(零診)數(shù)學(xué)試卷(含答案)
- 社會主義核心價值觀融入幼兒園班級管理課程教學(xué)探索
- 《公平競爭審查條例》微課
- 四年級下冊混合計算400題及答案
- 餐廳值班管理培訓(xùn)
- OQC出貨檢驗技能培訓(xùn)
- 旅游產(chǎn)業(yè)行業(yè)分析
評論
0/150
提交評論