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進階教程,全系列!

內容不錯的話但願你們支持鼓勵下點個贊/喜歡,歡迎一塊兒來交流;另外若是有什麼問題 建議 想看的內容能夠在評論提出

相關文章
相關標籤/搜索