博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Decorator Pattern With Laravel 装饰者模式
阅读量:6984 次
发布时间:2019-06-27

本文共 5622 字,大约阅读时间需要 18 分钟。

Decorator Pattern 装饰者模式

纲要:

1. 一个初学者的疑惑  2. 装饰者模式的特点  3. 简单case掌握装饰者模式  4. laravel中装饰者模式的应用

Confusing:

刚开始研究laravel源码之前,对于"装饰者模式"我也是知之甚少,而对于“装饰者模式”的学习起因于创建一个中间件的时候,我始终都不太明白,中间件中的$next闭包是怎么传进来,因此好奇心强的我google了大量的前辈的博客和文章,学到了很多以前不知道的知识点,才明白中间件加载的原理,使我受益匪浅,在此非常感谢这些前辈的无私奉献.ok,回到正题.

clipboard.png

装饰者模式的特点

“(1) 装饰对象和真实对象有相同的接口。这样客户端对象就能以和真实对象相同的方式和装饰对象交互。

(2) 装饰对象包含一个真实对象的引用(reference)
(3) 装饰对象接受所有来自客户端的请求。它把这些请求转发给真实的对象。
(4) 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。” --------------引自<百度百科>

简单case掌握装饰者模式

注意:若是以前没接触过该模式,建议先看下这篇文章,再回头看本文效果更佳.
好吧,如果是第一次看装饰者模式,看上面特性"官方阐述",确实有点不知所云,ok,为方便大家能快速理解该模式,我写了一个"laravel源码简化版"的case,放代码之前给大家说下实现该模式最核心的东西,就靠两个方法,如下:

  1. call_user_func()

  2. 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 '找了许久,仍未任何起色,突然有一天,碰见心仪的女神,结果,女神说:'."\n";};    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 '找了许久,仍未任何起色,突然有一天,碰见心仪的女神,结果,女神说:'."\n";}    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(Illuminate\Contracts\Http\Kernel::class);        $response = $kernel->handle(        $request = Illuminate\Http\Request::capture());文件Illuminate\Foundation\Http\Kernel.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);        };    }文件Illuminate\PipeLine\PipeLine.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));                }            };        };    }文件Illuminate\Foundation\Application.php        public function shouldSkipMiddleware()        {            return $this->bound('middleware.disable') &&                   $this->make('middleware.disable') === true;        }

转载地址:http://lmtpl.baihongyu.com/

你可能感兴趣的文章
XXX管理平台系统——概要
查看>>
常用思科设备图标(JPG+矢量图)
查看>>
倒排列表求交集算法 包括baeza yates的交集算法
查看>>
微信 登录 Scope 参数错误或没有 Scope 权限
查看>>
C# 温故知新 基础篇(7) 接口<思维导图>
查看>>
jQuery Makes Parsing XML Easy[转]
查看>>
CSS里常见的块级元素和行内元素
查看>>
Windows Azure Storage (4) Windows Azure Storage Service存储服务之Blob Share Access Signature
查看>>
framework调试
查看>>
java线程(2)--同步和锁
查看>>
Rafy 框架 - 大批量导入实体
查看>>
go1
查看>>
使用 Palette 让你的 UI 色彩与内容更贴合
查看>>
关于ASP.NET"未能映射路径"问题
查看>>
详谈如何定制自己的博客园皮肤
查看>>
iBATIS配置文件的特殊使用方法
查看>>
Python正则表达式指南
查看>>
T-SQL 根据年月日创建DateTime
查看>>
【CSS进阶】CSS 颜色体系详解
查看>>
论:CMMI项目策划方法(PP)
查看>>