php管道模式手测

一直在用Laravel框架,很喜欢laravel框架的中间件。在请求到结果之前,如果我们想要对路由或请求进行额外的处理,简单的加个Midleware中间件就行了,很简单,很方便是不是。
最近几天看了下它的中间件的实现方式,把自己的心得感悟写下来分享给大家。

了解管道模式

laravel的中间件用的是管道模式,我们先知道管道模式是什么:

所谓管道(Pipeline)设计模式就是将会数据传递到一个任务序列中,管道扮演者流水线的角色,数据在这里被处理然后传递到下一个步骤

管道,顾名思义,就是一个长长的流水管道,只不过加了许多阀门。所以管道模式大致需要三个角色:管道,阀门和载荷(流水)。如下图:
图片描述

管道模式UML模型图

开始代码之前,我们必须先了解管道模式的模型图
图片描述

简单的实现

根据上面的模型图,我们来实现自己所理解的管道模式的代码:

/**
 * PipelineBuilder 接口 即管道
 * @method pipe 存入多个阀门
 * @method process 输出
 */
interface PipelineBuilderInterface
{
    public function __construct($payload);
    public function pipe(StageBuilderInterface $stage);
    public function process();
}
// 具体的管道类
class Pipeline implements PipelineBuilderInterface
{
    protected $payload;
    protected $pipes = [];
    public function __construct($payload)
    {
        $this->payload = $payload;
    }

    public function pipe(StageBuilderInterface $stage)
    {
        $this->pipes[] = $stage;

        return $this;
    }

    public function process()
    {
        foreach ($this->pipes as $pipe) {
            call_user_func([$pipe, 'handle'], $this->payload);
        }
    }
}
// 阀门接口
interface StageBuilderInterface
{
    public function handle($payload);
}
// 具体的阀门类
class StageOneBuilder implements StageBuilderInterface
{
    public function handle($payload)
    {
        echo $payload .' 真是个';
    }
}
// 具体的阀门类
class StageTwoBuilder implements StageBuilderInterface
{
    public function handle($payload)
    {
        echo '帅气的男人';
    }
}
// 输出:我真是个帅气的男人
$pipeline = new Pipeline('我');
$pipeline->pipe(new StageOneBuilder)
    ->pipe(new StageTwoBuilder)
    ->process();

底层源码

先来看看它的底层源码:

return (new Pipeline($this->container))
            ->send($request)
            ->through($middleware)
            ->then(function ($request) use ($route) {
                return $this->prepareResponse(
                    $request, $route->run()
                );
            });

上面的代码是处理request请求的一部分代码,send()获取待处理的数据,through()获取中间件,then()传递闭包函数。
基本上,使用laravel pipelines你可以将一个实例对象(object)在多个类之间传递,就像流水顺着管道依次流淌一般,最终呢,层层传递,你就得到了从头至尾一系列执行操作的“最终”结果。

模仿laravel pipeline

interface PipelineInterface
{
    public function send($traveler);
    public function through($stops);
    public function via($method);
    public function process();
}

interface StageInterface
{
    public function handle($payload);
}

class StageOne implements StageInterface
{
    public function handle($payload) 
    {
        echo $payload . ' am really an ';
    }
} 

class StageTwo implements StageInterface
{
    public function handle($payload) {
        echo 'awesome man';
    }
} 

class Pipe implements PipelineInterface
{
    protected $container;
    protected $passable;
    protected $pipes = [];
    protected $via = 'handle';

    public function __construct($container)
    {
        $this->container = $container;
    }

    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 via($method)
    {
        $this->via = $method;

        return $this;
    }

    public function process()
    {
        foreach ($this->pipes as $pipe) {
            // 返回处理后的结果
            $this->passable = call_user_func([$pipe, $this->via], $this->passable);
        }
    }
}
$container = 'a';
$payload = 'wa';
$pipe = new Pipe($container);

// 输出:I am really an awesome man
$pipe->send($payload)->through([(new StageOne), (new StageTwo)])->process();

结语

上面的代码并没有达到laravel中间件的真正执行部分,例子中只是用到了管道模式的一部分。像then()方法中还用了array_reducearray_reverse函数来处理请求,这一部分有时间会进一步研究。

你可能感兴趣的:(设计模式,管道,php)