摘要:但是,這是不是又有點(diǎn)熟悉的感覺和上面第一次用工廠類的時(shí)候一樣依賴于工廠。在框架開發(fā)中也會把反射與依賴注入控制反轉(zhuǎn)搭配使用,讓程序有強(qiáng)大的可控性和擴(kuò)展性。博客鏈接淺談依賴注入與控制反轉(zhuǎn)
前言:設(shè)計(jì)模式其實(shí)是一個(gè)很空洞的東西,設(shè)計(jì)模式有幾十種,有些人覺得工廠模式也單例模式已經(jīng)足夠解決大部分問題。而有些人覺得任何設(shè)計(jì)模式都會讓開發(fā)變得更“復(fù)雜”,更“低效”。所以千萬不要太過追求他的實(shí)際意義和作用,否則你已經(jīng)墜入云霧。但是不管怎么樣,實(shí)際工作中還是要對它們有所了解,下面從php的角度來講一下依賴注入、控制反轉(zhuǎn)、反射等概念。如有錯(cuò)誤之處,還望路過大神多加指點(diǎn)
首先設(shè)定場景,假如一個(gè)類需要數(shù)據(jù)庫連接,最簡單的做法可能是:
class example { private $_db; function __construct(){ include "./Lib/Db.php"; $this->_db = new Db("localhost","root","123456","test"); } function getList(){ $this->_db->query("......"); } }
但事實(shí)上稍微有點(diǎn)經(jīng)驗(yàn)的同學(xué)都不會這樣寫,因?yàn)橐坏┰絹碓蕉嗟念愑玫絛b,而db一旦發(fā)生變化,那么豈不是要每個(gè)文件都修改一遍?這就是程序設(shè)計(jì)中的耦合問題。所有的類過度依賴 "./Lib/Db.php" 這個(gè)文件。OK,為了解決這個(gè)問題,工廠模式出現(xiàn)了,我們新建一個(gè) Factory 工廠類:
class Factory { public static function getDb(){ include "./Lib/Db.php"; return new Db("localhost","root","123456","test"); } } class example { private $_db; function __construct(){ $this->_db = Factory::getDb(); } function getList(){ $this->_db->query("......"); } }
如果我們用到db模塊那么直接 Factory::getDb() 從工廠中取出來就是了,看似解決了問題。但事實(shí)是這樣嗎?不,這樣只不過是把程序與 db 模塊的耦合轉(zhuǎn)移到了 Factory ,一旦后期業(yè)務(wù)發(fā)生變動,F(xiàn)actory 發(fā)生變動,依舊要對每個(gè)文件改動。那如何解決呢?
我們可以不從example類內(nèi)部獲取db組件,我們從外部把db組件注入進(jìn)example類
class example { private $_db; function getList(){ $this->_db->query("......");//執(zhí)行查詢 } //從外部注入db連接 function setDb($connection){ $this->_db = $connection; } } $example = new example(); $example->setDb(Factory::getDb());//注入db連接 $example->getList();
這樣一來example就不用關(guān)心db組件怎么來的了,只用暴露一個(gè)注入方法即可。這就是 DI/依賴注入(Dependency Injection) , 不在內(nèi)部處理依賴關(guān)系,而是把依賴作為參數(shù)傳遞進(jìn)去,以降低程序的耦合性 。
然后我們的項(xiàng)目繼續(xù)進(jìn)行,用到了文件處理類,圖像處理類,我們可能會這樣寫
$example->setDb(Factory::getDb());//注入db連接 $example->setFile(Factory::getFile());//注入文件處理類 $example->setImage(Factory::getImage());//注入Image處理類
但是這樣似乎也不行啊,每次都要寫這么多代碼,于是我們又寫了一個(gè)工廠方法
class Factory { public static function getExample(){ $example = new example(); $example->setDb(Factory::getDb());//注入db連接 $example->setFile(Factory::getFile());//注入文件處理類 $example->setImage(Factory::getImage());//注入Image處理類 return $expample; } }
example也不直接new 了。我們用 Factory::getExample()中獲取。但是,這是不是又有點(diǎn)熟悉的感覺?和上面第一次用工廠類的時(shí)候一樣依賴于工廠。于是又有了容器的概念。
class example { private $_di; function __construct(Di &$di){ $this->_di = $di; } //通過di容器獲取db實(shí)例 function getList(){ $this->_di->get("db")->query("......"); } } $di = new Di(); $di->set("db",function(){ return new Db("localhost","root","root","test"); }); $example = new example($di); $example->getList();
Di就是一個(gè)存放各種可擴(kuò)展的組件的容器,需要注入的時(shí)候調(diào)用$di->set()方法注入組件即可。程序中即可通過$di->get() 獲取組件。這樣被調(diào)用的組件(db)并不是由調(diào)用者(example)創(chuàng)建,而是由Di容器創(chuàng)建, 調(diào)用者失去控制權(quán),而容器得到控制權(quán),發(fā)生了控制權(quán)轉(zhuǎn)移 ,所以叫 做控制反轉(zhuǎn)(Inversion of Control)
但是這樣又有一些比較有強(qiáng)迫癥的同學(xué)發(fā)現(xiàn)了,每個(gè)類都要注入一遍容器是不是有些麻煩。沒錯(cuò),其實(shí)注入容器這個(gè)動作可以交給另外的程序處理,那就是反射。
_di->get("db")->query("......"); } } //di容器 class Di{ public $_container; public function get($cls){ return $this->_container[$cls]; } public function set($cls,$_instance){ $this->_container[$cls]=$_instance; } } //db組件 class db{ private static $_instance;//保存單例 //單例方法 public static function getInstance(){ if(!(self::$_instance instanceof self)){ self::$_instance = new self; } return self::$_instance; } //查詢方法 public function query($sql){ echo $sql; } } $di = new Di();//實(shí)例化容器 $di->set("db",db::getInstance()); //注入db實(shí)例 $reflector = new ReflectionClass("example"); //反射example,通過反射可以獲得該類的所有信息 $reflector->getDefaultProperties(); //example屬性 $reflector->getDocComment(); //注釋 $instance =$reflector->newInstanceArgs(); //相當(dāng)于實(shí)例化反射的example類 $instance->_di=$di; //注入di容器 $reflector->getmethod("getList")->invoke($instance);//調(diào)用example類方法
通過反射我們可以得到該類的全部信息,包括方法、方法名、屬性甚至注釋等等。通過反射我們可以方便的控制程序中使用的類,對他們進(jìn)行擴(kuò)展、修正、以及監(jiān)聽。通常反射在插件開發(fā)和框架開發(fā)中大量應(yīng)用。在框架開發(fā)中也會把反射與依賴注入、控制反轉(zhuǎn)搭配使用,讓程序有強(qiáng)大的可控性和擴(kuò)展性。
博客鏈接:淺談依賴注入與控制反轉(zhuǎn)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/23013.html
摘要:如何實(shí)現(xiàn)持久化持久化,將在內(nèi)存中的的狀態(tài)保存到硬盤中,相當(dāng)于備份數(shù)據(jù)庫狀態(tài)。相當(dāng)于備份數(shù)據(jù)庫接收到的命令,所有被寫入的命令都是以的協(xié)議格式來保存的。 最近社區(qū)里面有一篇文章引起了最多程序猿的關(guān)注,Laravel、PHPer 面試可能會遇到的問題,看評論區(qū)不少小伙伴們被難倒,對于一些問題同樣難倒了我(其實(shí)有很多啦),趁著周末有空,又總結(jié)梳理了一遍,順便來答一波題。由于個(gè)人技術(shù)水平有限,答...
摘要:控制反轉(zhuǎn)和依賴注入的關(guān)系也已經(jīng)清晰了,它們本質(zhì)上可以說是一樣的,只是具體的關(guān)注點(diǎn)不同。我的博客地址參考資料控制反轉(zhuǎn)和依賴注入的理解那些年搞不懂的高深術(shù)語依賴倒置控制反轉(zhuǎn)依賴注入面向接口編程控制反轉(zhuǎn)和依賴注入 序 第一次了解到控制反轉(zhuǎn)(Inversion of Control)這個(gè)概念,是在學(xué)習(xí)Spring框架的時(shí)候。IOC和AOP作為Spring的兩大特征,自然是要去好好學(xué)學(xué)的。而依賴...
摘要:對象之間耦合度過高的系統(tǒng),必然會出現(xiàn)牽一發(fā)而動全身的情形。控制被反轉(zhuǎn)之后,獲得依賴對象的過程由自身管理變?yōu)榱擞扇萜髦鲃幼⑷搿S谑牵o控制反轉(zhuǎn)取了一個(gè)更合適的名字叫做依賴注入。 Spring還可以這么學(xué)--IoC(控制反轉(zhuǎn)) / DI(依賴注入)理解 聲明:文章的前三部分參考博文:https://www.cnblogs.com/Nouno...這篇文章首發(fā)是在我的個(gè)人微信訂閱號每天學(xué)編...
閱讀 1049·2021-09-13 10:29
閱讀 3396·2019-08-29 18:31
閱讀 2642·2019-08-29 11:15
閱讀 3020·2019-08-26 13:25
閱讀 1377·2019-08-26 12:00
閱讀 2314·2019-08-26 11:41
閱讀 3412·2019-08-26 10:31
閱讀 1493·2019-08-26 10:25