责任链模式,其目的是组织一个对象链处理一个如方法调用的请求。
当ConcreteHandler(具体的处理程序)不知道如何满足来自Client的请求时,或它的目的不是这个时,它会委派给链中的下一个Handler(处理程序)来处理。
这个设计模式通常和复合模式一起使用,其中有些叶子或容器对象默认委派操作给它们的父对象。另一个例子是,本地化通常是使用责任链处理的,当德语翻译适配器没有为翻译关键词找到合适的结果时,就返回到英语适配器或干脆直接显示关键词本身。
耦合减少到最低限度:Client类不知道由哪个具体的类来处理请求;在创建对象图时配置了链;ConcreteHandlers不知道哪个对象是它们的继承者。行为在对象之间分配是成功的,链中最近的对象有优先权和责任满足请求。
参与者:
◆Client(客户端):向Handler(处理程序)提交一个请求;
◆Handler(处理程序)抽象:接收一个请求,以某种方式满足它;
◆ConcreteHandlers(具体的处理程序):接收一个请求,设法满足它,如果不成功就委派给下一个处理程序。
下面的代码实现了一个最著名的责任链示例:多级缓存。
- <?php
- /**
- * 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";