PHP設計模式之責任鏈模式(Chain Of Responsibilities)程式碼例項大全(21)
阿新 • • 發佈:2020-09-17
目的
建立一個物件鏈來按指定順序處理呼叫。如果其中一個物件無法處理命令,它會委託這個呼叫給它的下一個物件來進行處理,以此類推。
例子
-
垃圾郵件過濾器。
-
日誌框架,每個鏈元素自主決定如何處理日誌訊息。
-
快取:例如第一個物件是一個 Memcached 介面例項,如果 “丟失” 它會委託資料庫介面處理這個呼叫。
-
Yii 框架: CFilterChain 是一個控制器行為過濾器鏈。執行點會有鏈上的過濾器逐個傳遞,並且只有當所有的過濾器驗證通過,這個行為最後才會被呼叫。
UML 圖
程式碼
- 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 網際網路架構師 50K 成長指南+行業問題解決總綱(持續更新)
面試10家公司,收穫9個offer,2020年PHP 面試問題
★如果喜歡我的文章,想與更多資深開發者一起交流學習的話,獲取更多大廠面試相關技術諮詢和指導,歡迎加入我們的群啊,暗號:phpzh(君羊號碼856460874)。
內容不錯的話希望大家支援鼓勵下點個贊/喜歡,歡迎一起來交流;另外如果有什麼問題 建議 想看的內容可以在評論提出