摘要:裝飾對象包含一個真實對象的引用裝飾對象接受所有來自客戶端的請求。裝飾對象可以在轉發這些請求以前或以后增加一些附加功能。在面向對象的設計中,通常是通過繼承來實現對給定類的功能擴展。
Decorator Pattern 裝飾者模式
綱要:
1. 一個初學者的疑惑 2. 裝飾者模式的特點 3. 簡單case掌握裝飾者模式 4. laravel中裝飾者模式的應用
Confusing:
剛開始研究laravel源碼之前,對于"裝飾者模式"我也是知之甚少,而對于“裝飾者模式”的學習起因于創建一個中間件的時候,我始終都不太明白,中間件中的$next閉包是怎么傳進來,因此好奇心強的我google了大量的前輩的博客和文章,學到了很多以前不知道的知識點,才明白中間件加載的原理,使我受益匪淺,在此非常感謝這些前輩的無私奉獻.ok,回到正題.
裝飾者模式的特點
詳細介紹點我
“(1) 裝飾對象和真實對象有相同的接口。這樣客戶端對象就能以和真實對象相同的方式和裝飾對象交互。
(2) 裝飾對象包含一個真實對象的引用(reference)
(3) 裝飾對象接受所有來自客戶端的請求。它把這些請求轉發給真實的對象。
(4) 裝飾對象可以在轉發這些請求以前或以后增加一些附加功能。這樣就確保了在運行時,不用修改給定對象的結構就可以在外部增加附加的功能。在面向對象的設計中,通常是通過繼承來實現對給定類的功能擴展?!? --------------引自<百度百科>
簡單case掌握裝飾者模式
注意:若是以前沒接觸過該模式,建議先看下這篇文章《laravel 框架關鍵技術解析》學習筆記之裝飾者模式,再回頭看本文效果更佳.
好吧,如果是第一次看裝飾者模式,看上面特性"官方闡述",確實有點不知所云,ok,為方便大家能快速理解該模式,我寫了一個"laravel源碼簡化版"的case,放代碼之前給大家說下實現該模式最核心的東西,就靠兩個方法,如下:
call_user_func() 不懂就點我
array_reduce() 你應該看看我
代碼:
interface func{ public static function handle($next); } class beauty implements func{ public static function say($next){ $next(); echo "我看不上屌絲"; } } class guy implements func{ public static function say($next){ echo "從前有個程序員想找個女朋友."; $next(); } } $e=[guy::class,beauty::class]; function getClosure(){ return function ($a,$b){ return function()use($a,$b){ $b::say($a); }; }; } $d = function(){ echo "找了許久,仍未任何起色,突然有一天,碰見心儀的女神,結果,女神說:"." ";}; call_user_func(array_reduce($e,getClosure(),$d));
先別著急看代碼,先讓代碼運行下,看看結果是什么怎么樣的?然后再去分析代碼, 效果會好一點.ok,為了照顧新手朋友,我把執行過程,給大家梳理一下吧.
執行流程:
第一步.
首先getClosure()函數調用返回的是一個閉包:
function($a,$b){ return function()use($a,$b){ return $b::say($a); } }
第二步.
將$d和$e[0]作為第一步返回結果的參數并且執行,返回結果:
function()use($a,$b){ #此時$b="guy" #$a = $d=function(){echo "找了許久,仍未任何起色,突然有一天,碰見心儀的女神,結果,女神說:"." ";} return $b::say($a); }
第三步.
將第二部的結果和$e[1]作為第一步返回結果的參數并且執行,返回結果:
function()use($a,$b){ #此時$b="beauty" $a="第二步驟返回結果" # $a = function()use($,"beacuty"){ # beauty::say(function()use("guy",$d){ # return guy::say($d); # }) # } return $b::say($a); }
第四步.執行call_user_func()調用array_reduce()返回的閉包即第三步的結果.
beauty::say($d) ==>$d()=>echo "從前有個程序員想找個女朋友."; =>echo ""找了許久,仍未任何起色,突然有一天,碰見心儀的女神,結果,女神說:"=>"我看不上屌絲"
執行過程類似如圖(仔細體會,好似洋蔥一樣,從最外層滲透進去到最內層,再從最內層到最外層):
laravel中裝飾者模式的應用
這里給出laravel框架的源碼進行對比分析.
文件index.php line 50 $kernel = $app->make(IlluminateContractsHttpKernel::class); $response = $kernel->handle( $request = IlluminateHttpRequest::capture() ); 文件IlluminateFoundationHttpKernel.php public function handle($request) { try { $request->enableHttpMethodParameterOverride(); $response = $this->sendRequestThroughRouter($request); } catch (Exception $e) { ....省略異常處理 } $this->app["events"]->fire("kernel.handled", [$request, $response]); return $response; } protected function sendRequestThroughRouter($request) { $this->app->instance("request", $request); Facade::clearResolvedInstance("request"); $this->bootstrap(); return (new Pipeline($this->app)) ->send($request) ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) ->then($this->dispatchToRouter()); } protected function dispatchToRouter() { return function ($request) { $this->app->instance("request", $request); return $this->router->dispatch($request); }; } 文件IlluminatePipeLinePipeLine.php public function send($passable) { $this->passable = $passable; return $this; } public function through($pipes) { $this->pipes = is_array($pipes) ? $pipes : func_get_args(); return $this; } public function then(Closure $destination) { $firstSlice = $this->getInitialSlice($destination); $pipes = array_reverse($this->pipes); return call_user_func( array_reduce($pipes, $this->getSlice(), $firstSlice), $this->passable ); } protected function getInitialSlice(Closure $destination) { return function ($passable) use ($destination) { return call_user_func($destination, $passable); }; } protected function getSlice() { return function ($stack, $pipe) { return function ($passable) use ($stack, $pipe) { // If the pipe is an instance of a Closure, we will just call it directly but // otherwise we"ll resolve the pipes out of the container and call it with // the appropriate method and arguments, returning the results back out. if ($pipe instanceof Closure) { return call_user_func($pipe, $passable, $stack); } else { list($name, $parameters) = $this->parsePipeString($pipe); return call_user_func_array([$this->container->make($name), $this->method], array_merge([$passable, $stack], $parameters)); } }; }; } 文件IlluminateFoundationApplication.php public function shouldSkipMiddleware() { return $this->bound("middleware.disable") && $this->make("middleware.disable") === true; }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/30576.html
摘要:裝飾者模式是在開放關閉原則下實現動態添加或減少功能提高程序的擴展性詳細介紹注本文可以作為學習裝飾者模式的基礎篇但是我個人更建議配套裝飾者模式來學習效果更佳本文中的例子是由框架關鍵技術解析中摘抄的。 裝飾者模式:是在開放-關閉原則下實現動態添加或減少功能,提高程序的擴展性.詳細介紹注: 本文可以作為學習裝飾者模式的基礎篇,但是我個人更建議配套Decorator Pattern With...
摘要:把和拼接在一起的場所是,所以需要造一個類,在其內部實現對的操作中實現了把原有的進過個的裝飾后得到的新的,新的還是的實現,還是原來的物種。 說明:Laravel中Middleware的實現主要利用了Decorator Pattern的設計,本文主要先學習下Decorator Pattern如何實現,為后面學習Middleware的設計做個鋪墊。Decorator Pattern和Adap...
摘要:源碼解析這個類的源碼主要就是文件的操作和文件屬性的操作,而具體的操作是通過每一個實現的,看其構造函數看以上代碼知道對于操作,實際上是通過的實例來實現的??梢钥聪碌氖褂蒙衔囊呀浾f了,使得對各種的操作變得更方便了,不管是還是得。 說明:本文主要學習下LeagueFlysystem這個Filesystem Abstract Layer,學習下這個package的設計思想和編碼技巧,把自己的一...
摘要:通常有兩種方式可以實現給一個類或對象增加行為繼承機制,使用繼承機制是給現有類添加功能的一種有效途徑,通過繼承一個現有類可以使得子類在擁有自身方法的同時還擁有父類的方法。 裝飾模式 (Decorator Pattern) 裝飾模式能夠實現動態的為對象添加功能,是從一個對象外部來給對象添加功能。通常有兩種方式可以實現給一個類或對象增加行為: 繼承機制,使用繼承機制是給現有類添加功能的一種...
摘要:相關設計模式裝飾者模式和代理模式裝飾者模式關注再一個對象上動態添加方法代理模式關注再對代理對象的控制訪問,可以對客戶隱藏被代理類的信息裝飾著模式和適配器模式都叫包裝模式關于新職責適配器也可以在轉換時增加新的職責,但主要目的不在此。 0x01.定義與類型 定義:裝飾模式指的是在不必改變原類文件和使用繼承的情況下,動態地擴展一個對象的功能。它是通過創建一個包裝對象,也就是裝飾來包裹真實的...
閱讀 2746·2021-11-16 11:45
閱讀 1654·2021-09-26 10:19
閱讀 2051·2021-09-13 10:28
閱讀 2803·2021-09-08 10:46
閱讀 1530·2021-09-07 10:13
閱讀 1525·2019-08-30 13:50
閱讀 1374·2019-08-30 11:17
閱讀 1455·2019-08-29 13:18