摸鱼时刻 - 5分钟玩耍设计模式(1)

一、装饰器模式

假设存在一个基础 Request 类,只提供 urlmethod 基础属性。然而我们还想记录其他额外属性,如 context 上下文。这时装饰器模式就可以派上用场了~

1. Request 类

<?php

namespace App\Request;

class Request
{
    private $url;
    private $method;

    public function __construct($url, $method)
    {
        $this->url = $url;
        $this->method = $method;
    }

    public function getUrl()
    {
        return $this->url;
    }

    public function getMethod()
    {
        return $this->method;
    }

    public function echo($msg)
    {
        echo "url: {$this->url}, method: {$this->method}, content: {$msg}\n";
    }
}

2. MoYuRequest 类

<?php

namespace App\Request;

class MoYuRequest extends Request
{
    private $request;
    private $context = [];

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

    public function withContext($key, $value)
    {
        $this->context[$key] = $value;
    }

    public function getContext($key)
    {
        return $this->context[$key] ?? null;
    }

    public function getMethod()
    {
        return $this->request->getMethod();
    }

    public function getUrl()
    {
        return $this->request->getUrl();
    }

    public function echo($msg)
    {
        $context = json_encode($this->context);
        echo "context: {$context}\n";
        $this->request->echo($msg);
    }
}

3. 看看效果

<?php

use App\Request\Request;
use App\Request\MoYuRequest;

class App
{
    public function run()
    {
        $req = new Request("http://localhost:8080/hello", "GET");
        $req->echo("hello~");

        // output:
        // url: http://localhost:8080/hello, method: GET, content: hello~

        $req = new MoYuRequest($req);
        $req->withContext("ctx", "233");
        $req->echo("hello~");

        // output:
        // context: {"ctx":"233"}
        // url: http://localhost:8080/hello, method: GET, content: hello~
    }
}

二、职责链模式

现在我们想对请求内容进行验证,只有满足一定条件的请求才能触达我们真正的业务~

1. Filters 接口

<?php

namespace App\Filter;

use App\Request\MoYuRequest;

interface Filters
{
    public function doFilter(MoYuRequest $request);
}

2. 简单定义几个实现

1. HeaderFilter 类

<?php

namespace App\Filter;

use App\Request\MoYuRequest;

class HeaderFilter implements Filters
{
    public function doFilter(MoYuRequest $request)
    {
        $header = $request->getContext("header");
        echo "==== header: {$header}\n";
        if ($header == null) {
            return false;
        }

        return true;
    }
}

2. MethodFilter 类

<?php

namespace App\Filter;

use App\Request\MoYuRequest;

class MethodFilter implements Filters
{
    public function doFilter(MoYuRequest $request)
    {
        $method = $request->getMethod();
        echo "==== method: {$method}\n";
        if ($method == null || strtoupper($method) != "POST") {
            return false;
        }

        return true;
    }
}

3. FiltersChain 类

<?php

namespace App\Filter;

use App\Request\MoYuRequest;

class FiltersChain implements Filters
{
    private $filterList = [];

    public function addFilter(Filters $filters) 
    {
        array_push($this->filterList, $filters);
    }

    public function doFilter(MoYuRequest $request)
    {
        foreach ($this->filterList as $filter) {
            if (!$filter->doFilter($request)) {
                return false;
            }
        }

        return true;
    }
}

4. 看看效果

<?php

use App\Request\Request;
use App\Request\MoYuRequest;
use App\Filter\FiltersChain;
use App\Filter\HeaderFilter;
use App\Filter\MethodFilter;

class App
{
    public function run()
    {
        $req = new Request("http://localhost:8080/hello", "GET");
        $req = new MoYuRequest($req);
        $req->withContext("header", "233");
        $this->hello($req);

        // output:
        // ==== header: 233
        // ==== method: GET
        // filter error
    }

    public function hello(MoYuRequest $request)
    {
        $chain = new FiltersChain();
        $chain->addFilter(new HeaderFilter());
        $chain->addFilter(new MethodFilter());
        if (!$chain->doFilter($request)) {
            echo "filter error" . "\n";
            return;
        }

        $request->echo("hello~");
    }
}

end~

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!