PHP设计模式之责任链模式(Chain Of Responsibilities)代码实例大全(21)

目的

创建一个对象链来按指定顺序处理调用。若是其中一个对象没法处理命令,它会委托这个调用给它的下一个对象来进行处理,以此类推。php

例子

  • 垃圾邮件过滤器。laravel

  • 日志框架,每一个链元素自主决定如何处理日志消息。面试

  • 缓存:例如第一个对象是一个 Memcached 接口实例,若是 “丢失” 它会委托数据库接口处理这个调用。sql

  • Yii 框架: CFilterChain 是一个控制器行为过滤器链。执行点会有链上的过滤器逐个传递,而且只有当全部的过滤器验证经过,这个行为最后才会被调用。shell

UML 图

★官方PHP高级学习交流社群「点击」管理整理了一些资料,BAT等一线大厂进阶知识体系备好(相关学习资料以及笔面试题)以及不限于:分布式架构、高可扩展、高性能、高并发、服务器性能调优、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql优化、shell脚本、Docker、微服务、Nginx等多个知识点高级进阶干货数据库

代码

  • Handler.php
<?php

namespace DesignPatterns\Behavioral\ChainOfResponsibilities;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

/**
 * 建立处理器抽象类 Handler 。
 */
abstract class Handler
{
    /**
     * @var Handler|null
     * 定义继承处理器
     */
    private $successor = null;

    /**
     * 输入集成处理器对象。
     */
    public function __construct(Handler $handler = null)
    {
        $this->successor = $handler;
    }

    /**
     * 经过使用模板方法模式这种方法能够确保每一个子类不会忽略调用继
     * 承。
     *
     * @param RequestInterface $request
     * 定义处理请求方法。
     * 
     * @return string|null
     */
    final public function handle(RequestInterface $request)
    {
        $processed = $this->processing($request);

        if ($processed === null) {
            // 请求还没有被目前的处理器处理 => 传递到下一个处理器。
            if ($this->successor !== null) {
                $processed = $this->successor->handle($request);
            }
        }

        return $processed;
    }

    /**
     * 声明处理方法。
     */
    abstract protected function processing(RequestInterface $request);
}
  • Responsible/FastStorage.php
<?php

namespace DesignPatterns\Behavioral\ChainOfResponsibilities\Responsible;

use DesignPatterns\Behavioral\ChainOfResponsibilities\Handler;
use Psr\Http\Message\RequestInterface;

/**
 * 建立 http 缓存处理类。
 */
class HttpInMemoryCacheHandler extends Handler
{
    /**
     * @var array
     */
    private $data;

    /**
     * @param array $data
     * 传入数据数组参数。
     * @param Handler|null $successor
     * 传入处理器类对象 $successor 。
     */
    public function __construct(array $data, Handler $successor = null)
    {
        parent::__construct($successor);

        $this->data = $data;
    }

    /**
     * @param RequestInterface $request
     * 传入请求类对象参数 $request 。
     * @return string|null
     * 
     * 返回缓存中对应路径存储的数据。
     */
    protected function processing(RequestInterface $request)
    {
        $key = sprintf(
            '%s?%s',
            $request->getUri()->getPath(),
            $request->getUri()->getQuery()
        );

        if ($request->getMethod() == 'GET' && isset($this->data[$key])) {
            return $this->data[$key];
        }

        return null;
    }
}
  • Responsible/SlowStorage.php
<?php

namespace DesignPatterns\Behavioral\ChainOfResponsibilities\Responsible;

use DesignPatterns\Behavioral\ChainOfResponsibilities\Handler;
use Psr\Http\Message\RequestInterface;

/**
 * 建立数据库处理器。
 */
class SlowDatabaseHandler extends Handler
{
    /**
     * @param RequestInterface $request
     * 传入请求类对象 $request 。
     * 
     * @return string|null
     * 定义处理方法,下面应该是个数据库查询动做,可是简单化模拟,直接返回一个 'Hello World' 字符串做查询结果。
     */
    protected function processing(RequestInterface $request)
    {
        // 这是一个模拟输出, 在生产代码中你应该调用一个缓慢的 (相对于内存来讲) 数据库查询结果。

        return 'Hello World!';
    }
}

测试

  • Tests/ChainTest.php
<?php

namespace DesignPatterns\Behavioral\ChainOfResponsibilities\Tests;

use DesignPatterns\Behavioral\ChainOfResponsibilities\Handler;
use DesignPatterns\Behavioral\ChainOfResponsibilities\Responsible\HttpInMemoryCacheHandler;
use DesignPatterns\Behavioral\ChainOfResponsibilities\Responsible\SlowDatabaseHandler;
use PHPUnit\Framework\TestCase;

/**
 * 建立一个自动化测试单元 ChainTest 。
 */
class ChainTest extends TestCase
{
    /**
     * @var Handler
     */
    private $chain;

    /**
     * 模拟设置缓存处理器的缓存数据。
     */
    protected function setUp()
    {
        $this->chain = new HttpInMemoryCacheHandler(
            ['/foo/bar?index=1' => 'Hello In Memory!'],
            new SlowDatabaseHandler()
        );
    }

    /**
     * 模拟从缓存中拉取数据。
     */
    public function testCanRequestKeyInFastStorage()
    {
        $uri = $this->createMock('Psr\Http\Message\UriInterface');
        $uri->method('getPath')->willReturn('/foo/bar');
        $uri->method('getQuery')->willReturn('index=1');

        $request = $this->createMock('Psr\Http\Message\RequestInterface');
        $request->method('getMethod')
            ->willReturn('GET');
        $request->method('getUri')->willReturn($uri);

        $this->assertEquals('Hello In Memory!', $this->chain->handle($request));
    }

    /**
     * 模拟从数据库中拉取数据。
     */
    public function testCanRequestKeyInSlowStorage()
    {
        $uri = $this->createMock('Psr\Http\Message\UriInterface');
        $uri->method('getPath')->willReturn('/foo/baz');
        $uri->method('getQuery')->willReturn('');

        $request = $this->createMock('Psr\Http\Message\RequestInterface');
        $request->method('getMethod')
            ->willReturn('GET');
        $request->method('getUri')->willReturn($uri);

        $this->assertEquals('Hello World!', $this->chain->handle($request));
    }
}

PHP 互联网架构师成长之路*「设计模式」终极指南设计模式

PHP 互联网架构师 50K 成长指南+行业问题解决总纲(持续更新)数组

面试10家公司,收获9个offer,2020年PHP 面试问题缓存

★若是喜欢个人文章,想与更多资深开发者一块儿交流学习的话,获取更多大厂面试相关技术咨询和指导,欢迎加入咱们的群啊,暗号:phpzh(君羊号码856460874)。服务器

2020年最新PHP进阶教程,全系列!

内容不错的话但愿你们支持鼓励下点个赞/喜欢,欢迎一块儿来交流;另外若是有什么问题 建议 想看的内容能够在评论提出