PHP設(shè)計(jì)模式漫談之責(zé)任鏈模式
原創(chuàng)【51CTO獨(dú)家特稿】在上期的《PHP設(shè)計(jì)模式漫談》中,我們講到了PHP的代理模式,本節(jié)我們將繼續(xù)深入PHP設(shè)計(jì)模式,講解的行為模式是責(zé)任鏈模式,其目的是組織一個(gè)對(duì)象鏈處理一個(gè)如方法調(diào)用的請(qǐng)求。
當(dāng)ConcreteHandler(具體的處理程序)不知道如何滿足來(lái)自Client的請(qǐng)求時(shí),或它的目的不是這個(gè)時(shí),它會(huì)委派給鏈中的下一個(gè)Handler(處理程序)來(lái)處理。
這個(gè)設(shè)計(jì)模式通常和復(fù)合模式一起使用,其中有些葉子或容器對(duì)象默認(rèn)委派操作給它們的父對(duì)象。另一個(gè)例子是,本地化通常是使用責(zé)任鏈處理的,當(dāng)?shù)抡Z(yǔ)翻譯適配器沒(méi)有為翻譯關(guān)鍵詞找到合適的結(jié)果時(shí),就返回到英語(yǔ)適配器或干脆直接顯示關(guān)鍵詞本身。
耦合減少到最低限度:Client類不知道由哪個(gè)具體的類來(lái)處理請(qǐng)求;在創(chuàng)建對(duì)象圖時(shí)配置了鏈;ConcreteHandlers不知道哪個(gè)對(duì)象是它們的繼承者。行為在對(duì)象之間分配是成功的,鏈中最近的對(duì)象有優(yōu)先權(quán)和責(zé)任滿足請(qǐng)求。
參與者:
◆Client(客戶端):向Handler(處理程序)提交一個(gè)請(qǐng)求;
◆Handler(處理程序)抽象:接收一個(gè)請(qǐng)求,以某種方式滿足它;
◆ConcreteHandlers(具體的處理程序):接收一個(gè)請(qǐng)求,設(shè)法滿足它,如果不成功就委派給下一個(gè)處理程序。
下面的代碼實(shí)現(xiàn)了一個(gè)最著名的責(zé)任鏈?zhǔn)纠憾嗉?jí)緩存。
- /**
- * The Handler abstraction. Objects that want to be a part of the
- * ChainOfResponsibility must implement this interface directly or via
- * inheritance from an AbstractHandler.
- */
- interface KeyValueStore
- {
- /**
- * Obtain a value.
- * @param string $key
- * @return mixed
- */
- public function get($key);
- }
- /**
- * Basic no-op implementation which ConcreteHandlers not interested in
- * caching or in interfering with the retrieval inherit from.
- */
- abstract class AbstractKeyValueStore implements KeyValueStore
- {
- protected $_nextHandler;
- public function get($key)
- {
- return $this->_nextHandler->get($key);
- }
- }
- /**
- * Ideally the last ConcreteHandler in the chain. At least, if inserted in
- * a Chain it will be the last node to be called.
- */
- class SlowStore implements KeyValueStore
- {
- /**
- * This could be a somewhat slow store: a database or a flat file.
- */
- protected $_values;
- public function __construct(array $values = array())
- {
- $this->_values = $values;
- }
- public function get($key)
- {
- return $this->_values[$key];
- }
- }
- /**
- * A ConcreteHandler that handles the request for a key by looking for it in
- * its own cache. Forwards to the next handler in case of cache miss.
- */
- class InMemoryKeyValueStore implements KeyValueStore
- {
- protected $_nextHandler;
- protected $_cached = array();
- public function __construct(KeyValueStore $nextHandler)
- {
- $this->_nextHandler = $nextHandler;
- }
- protected function _load($key)
- {
- if (!isset($this->_cached[$key])) {
- $this->_cached[$key] = $this->_nextHandler->get($key);
- }
- }
- public function get($key)
- {
- $this->_load($key);
- return $this->_cached[$key];
- }
- }
- /**
- * A ConcreteHandler that delegates the request without trying to
- * understand it at all. It may be easier to use in the user interface
- * because it can specialize itself by defining methods that generates
- * html, or by addressing similar user interface concerns.
- * Some Clients see this object only as an instance of KeyValueStore
- * and do not care how it satisfy their requests, while other ones
- * may use it in its entirety (similar to a class-based adapter).
- * No client knows that a chain of Handlers exists.
- */
- class FrontEnd extends AbstractKeyValueStore
- {
- public function __construct(KeyValueStore $nextHandler)
- {
- $this->_nextHandler = $nextHandler;
- }
- public function getEscaped($key)
- {
- return htmlentities($this->get($key), ENT_NOQUOTES, 'UTF-8');
- }
- }
- // Client code
- $store = new SlowStore(array('pd' => 'Philip K. Dick',
- 'ia' => 'Isaac Asimov',
- 'ac' => 'Arthur C. Clarke',
- 'hh' => 'Helmut Heißenbüttel'));
- // in development, we skip cache and pass $store directly to FrontEnd
- $cache = new InMemoryKeyValueStore($store);
- $frontEnd = new FrontEnd($cache);
- echo $frontEnd->get('ia'), "\n";
- echo $frontEnd->getEscaped('hh'), "\n";
關(guān)于PHP責(zé)任鏈設(shè)計(jì)模式的一些實(shí)現(xiàn)說(shuō)明:
◆責(zé)任鏈可能已經(jīng)存在于對(duì)象圖中,和復(fù)合模式的例子一樣;
◆此外,Handler抽象可能存在,也可能不存在,最好的選擇是一個(gè)分開(kāi)的Handler接口只可以執(zhí)行handleRequest()操作,不要強(qiáng)制一個(gè)鏈只在一個(gè)層次中,因?yàn)楹竺娴囊呀?jīng)存在了;
◆也可能引入一個(gè)抽象類,但由于請(qǐng)求處理是一個(gè)正交關(guān)注,因此具體的類可能已經(jīng)繼承了其它類;
◆通過(guò)constructor 或setter,Handler(或下一個(gè)Handler)被注入到Client或前一個(gè)Handler;
◆請(qǐng)求對(duì)象通常是一個(gè)ValueObject,也可能被實(shí)現(xiàn)為一個(gè)Flyweight,在PHP中,它可能是一個(gè)標(biāo)量類型,如string,注意在某些語(yǔ)言中,一個(gè)string就是一個(gè)不變的ValueObject。
簡(jiǎn)單的總結(jié)責(zé)任鏈模式,可以歸納為:用一系列類(classes)試圖處理一個(gè)請(qǐng)求request,這些類之間是一個(gè)松散的耦合,唯一共同點(diǎn)是在他們之間傳遞request. 也就是說(shuō),來(lái)了一個(gè)請(qǐng)求,A類先處理,如果沒(méi)有處理,就傳遞到B類處理,如果沒(méi)有處理,就傳遞到C類處理,就這樣象一個(gè)鏈條(chain)一樣傳遞下去。
51CTO會(huì)在下周繼續(xù)深入PHP設(shè)計(jì)模式,講解PHP中的結(jié)構(gòu)化模式摘要,敬請(qǐng)關(guān)注。
【編輯推薦】
- PHP設(shè)計(jì)模式漫談之代理模式
- 使用設(shè)計(jì)模式改善程序結(jié)構(gòu)
- 架構(gòu)、框架、設(shè)計(jì)模式之間的關(guān)系簡(jiǎn)述
- 鐘勝輝談PHP發(fā)展的現(xiàn)狀和前景
- 揭示PHP成功背后的秘密:PHP創(chuàng)始人訪談錄
原文:Practical Php Patterns: Chain of Responsibility 作者:Giorgio
鏈接:http://giorgiosironi.blogspot.com/2010/02/practical-php-patterns-chain-of.html