摘要:的優(yōu)美得益于開發(fā)的組件式解耦,這與服務(wù)容器和服務(wù)提供者的理念是離不開的,下篇將用框架中類來梳理服務(wù)容器的工作流程。
原文:blog,轉(zhuǎn)載注明來源即可。
本文代碼:GitHub
服務(wù)容器是 Laravel 框架實(shí)現(xiàn)模塊化解耦的核心。模塊化即是將系統(tǒng)拆成多個(gè)子模塊,子模塊間的耦合程度盡可能的低,代碼中盡可能的避免直接調(diào)用。這樣才能提高系統(tǒng)的代碼重用性、可維護(hù)性、擴(kuò)展性。
下邊出行例子有火車、飛機(jī)兩種出行方式,對(duì)應(yīng)給出了 3 種耦合度越來越低的實(shí)現(xiàn):高度耦合實(shí)現(xiàn)、工廠模式解耦、IOC 模式解耦。
高度耦合實(shí)現(xiàn) 代碼實(shí)現(xiàn)定義 TrafficTool 接口并用 Train、Plane 實(shí)現(xiàn),最后在 Traveler 中實(shí)例化出行工具后說走就走。代碼十分簡(jiǎn)潔:
travelTool = new Train(); } public function travel() { $this->travelTool->go(); } } $me = new Traveler(); $me->travel();
運(yùn)行:
$ php normal.php [Travel By]: train優(yōu)點(diǎn)
代碼十分簡(jiǎn)潔:一個(gè)接口兩個(gè)類最后直接調(diào)用。
缺點(diǎn)在第 32 行,Traveler 與 Train 兩個(gè)組件發(fā)生了耦合。以后想坐飛機(jī)出行,必須修改 __construct() 的內(nèi)部實(shí)現(xiàn):$this->travelTool = new Plane();
重用性和可維護(hù)性都很差:在實(shí)際的軟件開發(fā)中,代碼會(huì)根據(jù)業(yè)務(wù)需求的變化而不斷修改。如果組件之間直接相互調(diào)用,那組件的代碼就不能輕易修改,以免調(diào)用它的地方出現(xiàn)錯(cuò)誤。
工廠模式解耦 工廠模式分離代碼中不變和變的部分,使得在不同條件下創(chuàng)建不同的對(duì)象。
代碼實(shí)現(xiàn)... class TrafficToolFactory { public function create($name) { switch ($name) { case "train": return new Train(); case "plane": return new Plane(); default: exit("[No Traffic Tool] :" . $name); } } } // 旅游者類,使用火車出行 class Traveler { protected $trafficTool; public function __construct($toolName) { // 使用工廠類實(shí)例化需要的交通工具 $factory = new TrafficToolFactory(); $this->travelTool = $factory->create($toolName); } public function travel() { $this->travelTool->go(); } } // 傳入指定的方式 $me = new Traveler("train"); $me->travel();
運(yùn)行:
$ php factory.php [Travel By]: train優(yōu)點(diǎn)
提取了代碼中變化的部分:更換交通工具,坐飛機(jī)出行直接修改 $me = new Traveler("plane") 即可。適用于需求簡(jiǎn)單的情況。
缺點(diǎn)依舊沒有徹底解決依賴:現(xiàn)在 Traveler 與 TrafficToolFactory 發(fā)生了依賴。當(dāng)需求增多后,工廠的 switch...case 等代碼也不易維護(hù)。
IOC 模式解耦IOC 是 Inversion Of Controll 的縮寫,即控制反轉(zhuǎn)。這里的“反轉(zhuǎn)”可理解為將組件間依賴關(guān)系提到外部管理。
簡(jiǎn)單的依賴注入依賴注入是 IOC 的一種實(shí)現(xiàn)方式,是指組件間的依賴通過外部參數(shù)(interface)形式直接注入。比如對(duì)上邊的工廠模式進(jìn)一步解耦:
trafficTool = $tool; } public function travel() { $this->trafficTool->go(); } } $train = new Train(); $me = new Traveler($train); // 將依賴直接以參數(shù)的形式注入 $me->travel();
運(yùn)行:
$ php simple_ioc.php [Travel By]: train高級(jí)依賴注入 簡(jiǎn)單注入的問題
如果三個(gè)人分別自駕游、坐飛機(jī)、高鐵出去玩,那你的代碼可能是這樣的:
$train = new Train(); $plane = new Plane(); $car = new Car(); $a = new Traveler($car); $b = new Traveler($plane); $c = new Traveler($train); $a->travel(); $b->travel(); $c->travel();
看起來就兩個(gè)字:藍(lán)瘦。上邊簡(jiǎn)單的依賴注入相比工廠模式已經(jīng)解耦挺多了,參考 Laravel 中服務(wù)容器的概念,還能繼續(xù)解耦。將會(huì)使用到 PHP 反射和匿名函數(shù),參考:Laravel 框架中常用的 PHP 語法
IOC 容器高級(jí)依賴注入 = 簡(jiǎn)單依賴注入 + IOC 容器
binds[$abstract] = $concrete; } else { $this->instances[$abstract] = $concrete; } } /** * 生產(chǎn):執(zhí)行回調(diào)函數(shù) * * @param $abstract 字符指令 * @param array $params 回調(diào)函數(shù)所需參數(shù) * @return mixed 回調(diào)函數(shù)的返回值 */ public function make($abstract, $params = []) { if (isset($this->instances[$abstract])) { return $this->instances[$abstract]; } // 此時(shí) $this 是有 2 個(gè)元素的數(shù)組 // Array ( // [0] => Container Object ( // [binds] => Array ( ... ) // [instances] => Array() // ) // [1] => "train" // ) array_unshift($params, $this); // 將參數(shù)傳遞給回調(diào)函數(shù) return call_user_func_array($this->binds[$abstract], $params); } } $container = new Container(); $container->bind("traveler", function ($container, $trafficTool) { return new Traveler($container->make($trafficTool)); }); $container->bind("train", function ($container) { return new Train(); }); $container->bind("plane", function ($container) { return new Plane(); }); $me = $container->make("traveler", ["train"]); $me->travel();
運(yùn)行:
$ php advanced_ioc.php [Travel By]: train簡(jiǎn)化并解耦后的代碼
那三個(gè)人再出去玩,代碼將簡(jiǎn)化為:
$a = $container->make("traveler", ["car"]); $b = $container->make("traveler", ["train"]); $c = $container->make("traveler", ["plane"]); $a->travel(); $b->travel(); $c->travel();
更多參考:神奇的服務(wù)容器
Laravel 的服務(wù)容器Laravel 自己的服務(wù)容器是一個(gè)更加高級(jí)的 IOC 容器,它的簡(jiǎn)化代碼如下:
getClosure($abstract, $concrete); } $this->binds[$abstract] = compact("concrete", "shared"); } // 獲取回調(diào)函數(shù) public function getClosure($abstract, $concrete) { return function ($container) use ($abstract, $concrete) { $method = ($abstract == $concrete) ? "build" : "make"; return $container->$method($concrete); }; } protected function getConcrete($abstract) { if (!isset($this->binds[$abstract])) { return $abstract; } return $this->binds[$abstract]["concrete"]; } // 生成實(shí)例對(duì)象 public function make($abstract) { $concrete = $this->getConcrete($abstract); if ($this->isBuildable($abstract, $concrete)) { $obj = $this->build($concrete); } else { $obj = $this->make($concrete); } return $obj; } // 判斷是否要用反射來實(shí)例化 protected function isBuildable($abstract, $concrete) { return $concrete == $abstract || $concrete instanceof Closure; } // 通過反射來實(shí)例化 $concrete 的對(duì)象 public function build($concrete) { if ($concrete instanceof Closure) { return $concrete($this); } $reflector = new ReflectionClass($concrete); if (!$reflector->isInstantiable()) { echo "[can"t instantiable]: " . $concrete; } $constructor = $reflector->getConstructor(); // 使用默認(rèn)的構(gòu)造函數(shù) if (is_null($constructor)) { return new $concrete; } $refParams = $constructor->getParameters(); $instances = $this->getDependencies($refParams); return $reflector->newInstanceArgs($instances); } // 獲取實(shí)例化對(duì)象時(shí)所需的參數(shù) public function getDependencies($refParams) { $deps = []; foreach ($refParams as $refParam) { $dep = $refParam->getClass(); if (is_null($dep)) { $deps[] = null; } else { $deps[] = $this->resolveClass($refParam); } } return (array)$deps; } // 獲取參數(shù)的類型類名字 public function resolveClass(ReflectionParameter $refParam) { return $this->make($refParam->getClass()->name); } } $container = new Container(); // 將 traveller 對(duì)接到 Train $container->bind("TrafficTool", "Train"); $container->bind("traveller", "Traveller"); // 創(chuàng)建 traveller 實(shí)例 $me = $container->make("traveller"); $me->travel();
運(yùn)行:
$ php laravel_ioc.php [Travel By]: train
Train 類要能被實(shí)例化,需要先注冊(cè)到容器,這就涉及到 Laravel 中服務(wù)提供者(Service Provider)的概念了。至于服務(wù)提供者是怎么注冊(cè)類、注冊(cè)之后如何實(shí)例化、實(shí)例化后如何調(diào)用的... 下節(jié)詳細(xì)分析。
總結(jié)本文用一個(gè)旅游出行的 demo,引出了高度耦合的直接實(shí)現(xiàn)、工廠模式解耦和 IOC 模式解耦共計(jì)三種實(shí)現(xiàn)方式,越往后代碼量越多還有些繞,但類(模塊)之間的耦合度越來越低,最后實(shí)現(xiàn)了簡(jiǎn)化版的 Laravel 服務(wù)容器。
Laravel 的優(yōu)美得益于開發(fā)的組件式解耦,這與服務(wù)容器和服務(wù)提供者的理念是離不開的,下篇將用 Laravel 框架 laravel/framework/src/Illuminate/Container.php 中 Container 類來梳理 Laravel 服務(wù)容器的工作流程。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/28798.html
摘要:可以為服務(wù)提供者的方法設(shè)置類型提示。方法將在所有其他服務(wù)提供者均已注冊(cè)之后調(diào)用。所有服務(wù)提供者都在配置文件中注冊(cè)??梢赃x擇推遲服務(wù)提供者的注冊(cè),直到真正需要注冊(cè)綁定時(shí),這樣可以提供應(yīng)用程序的性能。 本文最早發(fā)布于 Rootrl的Blog 導(dǎo)言 Laravel是一款先進(jìn)的現(xiàn)代化框架,里面有一些概念非常重要。在上手Laravel之前,我認(rèn)為先弄懂這些概念是很有必要的。你甚至需要重溫下PHP...
摘要:依賴注入依賴注入一詞是由提出的術(shù)語,它是將組件注入到應(yīng)用程序中的一種行為。就像說的依賴注入是敏捷架構(gòu)中關(guān)鍵元素。類依賴于,所以我們的代碼可能是這樣的創(chuàng)建一個(gè)這是一種經(jīng)典的方法,讓我們從使用構(gòu)造函數(shù)注入開始。 showImg(https://segmentfault.com/img/remote/1460000018806800); 文章轉(zhuǎn)自:https://learnku.com/la...
摘要:劃下重點(diǎn),服務(wù)容器是用于管理類的依賴和執(zhí)行依賴注入的工具。類的實(shí)例化及其依賴的注入,完全由服務(wù)容器自動(dòng)的去完成。 本文首發(fā)于 深入剖析 Laravel 服務(wù)容器,轉(zhuǎn)載請(qǐng)注明出處。喜歡的朋友不要吝嗇你們的贊同,謝謝。 之前在 深度挖掘 Laravel 生命周期 一文中,我們有去探究 Laravel 究竟是如何接收 HTTP 請(qǐng)求,又是如何生成響應(yīng)并最終呈現(xiàn)給用戶的工作原理。 本章將帶領(lǐng)大...
摘要:工廠模式,依賴轉(zhuǎn)移當(dāng)然,實(shí)現(xiàn)控制反轉(zhuǎn)的方法有幾種。其實(shí)我們稍微改造一下這個(gè)類,你就明白,工廠類的真正意義和價(jià)值了。雖然如此,工廠模式依舊十分優(yōu)秀,并且適用于絕大多數(shù)情況。 此篇文章轉(zhuǎn)載自laravel-china,chongyi的文章https://laravel-china.org/top...原文地址: http://www.insp.top/learn-lar... ,轉(zhuǎn)載務(wù)必保...
摘要:本文一大半內(nèi)容都是通過舉例來讓讀者去理解什么是控制反轉(zhuǎn)和依賴注入,通過理解這些概念,來更加深入。這種由外部負(fù)責(zé)其依賴需求的行為,我們可以稱其為控制反轉(zhuǎn)。工廠模式,依賴轉(zhuǎn)移當(dāng)然,實(shí)現(xiàn)控制反轉(zhuǎn)的方法有幾種。 容器,字面上理解就是裝東西的東西。常見的變量、對(duì)象屬性等都可以算是容器。一個(gè)容器能夠裝什么,全部取決于你對(duì)該容器的定義。當(dāng)然,有這樣一種容器,它存放的不是文本、數(shù)值,而是對(duì)象、對(duì)象的描...
閱讀 3156·2021-11-24 10:24
閱讀 2966·2021-11-11 16:54
閱讀 3086·2021-09-22 15:55
閱讀 2040·2019-08-30 15:44
閱讀 1910·2019-08-29 18:41
閱讀 2773·2019-08-29 13:43
閱讀 3063·2019-08-29 12:51
閱讀 1201·2019-08-26 12:19