1. 程式人生 > 實用技巧 >PHP設計模式之責任鏈模式(Chain Of Responsibilities)程式碼例項大全(21)

PHP設計模式之責任鏈模式(Chain Of Responsibilities)程式碼例項大全(21)

目的

建立一個物件鏈來按指定順序處理呼叫。如果其中一個物件無法處理命令,它會委託這個呼叫給它的下一個物件來進行處理,以此類推。

例子

  • 垃圾郵件過濾器。

  • 日誌框架,每個鏈元素自主決定如何處理日誌訊息。

  • 快取:例如第一個物件是一個 Memcached 介面例項,如果 “丟失” 它會委託資料庫介面處理這個呼叫。

  • Yii 框架: CFilterChain 是一個控制器行為過濾器鏈。執行點會有鏈上的過濾器逐個傳遞,並且只有當所有的過濾器驗證通過,這個行為最後才會被呼叫。

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

內容不錯的話希望大家支援鼓勵下點個贊/喜歡,歡迎一起來交流;另外如果有什麼問題 建議 想看的內容可以在評論提出