B5:责任链模式 Chain Of Responsibility
使多个对象都有机会处理处理请求,从而避免请求的发送者和接受者之间的耦合关系.将这个对象连成一条链,并沿着该链处理请求,直到有一个对象能够处理它为止.
相当于switch/case,在客户端指定了每一链的下一链.
UML
示例代码:
abstract class Handle { protected $nextHandle; public function setNextHandle(Handle $handle) { $this->nextHandle = $handle; } abstract public function handleRequest($level); } class Handle1 extends Handle { public function handleRequest($level) { if ($level > 0 && $level < 10) { echo 'Handle1 处理了'; } elseif(!is_null($this->nextHandle)) { $this->nextHandle->handleRequest($level); } } } class Handle2 extends Handle { public function handleRequest($level) { if ($level > 10 && $level < 100) { echo 'Handle2 处理了'; } elseif(!is_null($this->nextHandle)) { $this->nextHandle->handleRequest($level); } } } class Handle3 extends Handle { public function handleRequest($level) { if ($level > 100 && $level < 1000) { echo 'Handle3 处理了'; } elseif(!is_null($this->nextHandle)) { $this->nextHandle->handleRequest($level); } } } $handle1 = new Handle1(); $handle2 = new Handle2(); $handle3 = new Handle3(); $handle1->setNextHandle($handle2); $handle2->setNextHandle($handle3); $handle1->handleRequest(600);
这个手动设置下一处理者,还是有点不方便.有时候设置出错,容易导致死循环,我们改进一下.
示例代码:
abstract class Handle { abstract public function handleRequest($level); } class Handle1 extends Handle { public function handleRequest($level) { if ($level > 0 && $level < 10) { echo 'Handle1 处理了'; return true; } } } class Handle2 extends Handle { public function handleRequest($level) { if ($level > 10 && $level < 100) { echo 'Handle2 处理了'; return true; } } } class Handle3 extends Handle { public function handleRequest($level) { if ($level > 100 && $level < 1000) { echo 'Handle3 处理了'; return true; } } } class Context { protected $chains = []; public function addHandle(Handle $handle) { $this->chains[] = $handle; } public function handleRequest($level) { foreach ($this->chains as $handler) { if ($handler->handleRequest($level)) { break; } } } } $context = new Context(); $context->addHandle(new Handle1()); $context->addHandle(new Handle2()); $context->addHandle(new Handle3()); $context->handleRequest(600);
我们将链的设置交给Context,Context维护了一个数组来保存设置的处理者.context中的handleRequest方法,循环从数组中读取并处理.在每个处理者类中,我们让其如果有处理,就返回true,在foreach循环中跳出循环,防止无用的循环继续下去.
当然有时候我们需要职责链的每个处理者挨个处理请求,也可以使用这种方法.