摘要:装饰对象包含一个真实对象的引用装饰对象接受所有来自客户端的请求。装饰对象可以在转发这些请求以前或以后增加一些附加功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。
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; }
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/30576.html
摘要:装饰者模式是在开放关闭原则下实现动态添加或减少功能提高程序的扩展性详细介绍注本文可以作为学习装饰者模式的基础篇但是我个人更建议配套装饰者模式来学习效果更佳本文中的例子是由框架关键技术解析中摘抄的。 装饰者模式:是在开放-关闭原则下实现动态添加或减少功能,提高程序的扩展性.详细介绍注: 本文可以作为学习装饰者模式的基础篇,但是我个人更建议配套Decorator Pattern With...
摘要:把和拼接在一起的场所是,所以需要造一个类,在其内部实现对的操作中实现了把原有的进过个的装饰后得到的新的,新的还是的实现,还是原来的物种。 说明:Laravel中Middleware的实现主要利用了Decorator Pattern的设计,本文主要先学习下Decorator Pattern如何实现,为后面学习Middleware的设计做个铺垫。Decorator Pattern和Adap...
摘要:源码解析这个类的源码主要就是文件的操作和文件属性的操作,而具体的操作是通过每一个实现的,看其构造函数看以上代码知道对于操作,实际上是通过的实例来实现的。可以看下的使用上文已经说了,使得对各种的操作变得更方便了,不管是还是得。 说明:本文主要学习下LeagueFlysystem这个Filesystem Abstract Layer,学习下这个package的设计思想和编码技巧,把自己的一...
摘要:通常有两种方式可以实现给一个类或对象增加行为继承机制,使用继承机制是给现有类添加功能的一种有效途径,通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法。 装饰模式 (Decorator Pattern) 装饰模式能够实现动态的为对象添加功能,是从一个对象外部来给对象添加功能。通常有两种方式可以实现给一个类或对象增加行为: 继承机制,使用继承机制是给现有类添加功能的一种...
摘要:相关设计模式装饰者模式和代理模式装饰者模式关注再一个对象上动态添加方法代理模式关注再对代理对象的控制访问,可以对客户隐藏被代理类的信息装饰着模式和适配器模式都叫包装模式关于新职责适配器也可以在转换时增加新的职责,但主要目的不在此。 0x01.定义与类型 定义:装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的...
阅读 2746·2021-11-16 11:45
阅读 1653·2021-09-26 10:19
阅读 2050·2021-09-13 10:28
阅读 2803·2021-09-08 10:46
阅读 1528·2021-09-07 10:13
阅读 1525·2019-08-30 13:50
阅读 1374·2019-08-30 11:17
阅读 1455·2019-08-29 13:18