责任链模式
责任链模式又称为:职责链模式、命令链、CoR、Chain of Command、Chain of Responsibility。责任链是一种行为设计模式,允许将请求沿着处理者链进行发送。收到请求后,每个处理者均可对请求进行处理,或将其传递给链上的下个处理者。
问题
假设我们需要开发一个线下“PHP设计模式”培训课,办一个班,需要政府审批。
所以我们去了当地县教育局,县教育局回复说:“你们这个是要开一个培训学校,我们这不管新开,你去市教育局看看”;理所当然我们到了市教育局,“啊,你们要开一个培训学校呀?这个我们没有这个权限,需要去省教育局”市教育局工作人员介绍到;我们又去了省教育局,这回没有走错了,“你把你们培训什么内容以及办学规模,填表就可以等结果了”省教育局工作人员介绍到。
这样我们可能会一个函数中,我们每次去一个地,我们都需要记录,而每次新增功能都会使其更加 臃肿(代码变得越来越多,也越来越混乱)。修改某个 审批步骤 有时会影响其他的 审批步骤。最糟糕的是,系统会变得让人非常费解,而且其维护成本也会激增。在艰难地和这些代码共处一段时间后,有一天终于决定对整个系统进行重构。
解决方法
在上述示例中我们要一级级去问,能不能使用一个统一方法,自动一级级去问,只到有地方可以答应为主,每个 审批步骤 都可被抽取为仅有单个方法的类,并执行检查操作。请求及其数据则会被作为参数传递给该方法。
将这些处理者连成一条链。链上的每个处理者都有一个成员变量来保存对于下一处理者的引用。除了处理请求外,处理者还负责沿着链传递请求。请求会在链上移动,直至所有处理者都有机会对其进行处理。
处理者(教育局)接收到请求后自行决定是否能够对其进行处理。如果自己能够处理,处理者就不再继续传递请求。因此在这种情况下,每个请求要么最多有一个处理者对其进行处理,要么没有任何处理者对其进行处理。
结构
Handler:责任链接口基类; BaseHandler :实现 Handler 接口的抽象责任链类(可有可无); *EducationBureau:具体的责任链类 示例中指:县教育局、市教育局、省教育局;
代码示例
接口
代码语言:javascript复制interface Handler
{
/**
* 下一个请求
* @return mixed
* @author chendashengpc
*/
public function setNext(Handler $handler);
/**
* 当前处理
* @return mixed
* @author chendashengpc
*/
public function handler();
}
抽象类
代码语言:javascript复制abstract class BaseHandler implements Handler
{
/**
* 下一个请求类
* @var Handler
*/
protected Handler $next;
}
具体类
县教育局
代码语言:javascript复制/**
* 县教育局
*/
class CountyEducationBureau extends BaseHandler
{
/**
* 下一个请求
* @return mixed
* @author chendashengpc
*/
public function setNext(Handler $handler)
{
$this->next = $handler;
}
/**
* 当前处理
* @return mixed
* @author chendashengpc
*/
public function handler()
{
echo '我是县教育局,我这办不了,你去市教育局' . PHP_EOL;
if ($this->next != null) {
$this->next->handler();
}
}
}
市教育局
代码语言:javascript复制/**
* 市教育局
*/
class MunicipalEducationBureau extends BaseHandler
{
/**
* 下一个请求
* @return mixed
* @author chendashengpc
*/
public function setNext(Handler $handler)
{
$this->next = $handler;
}
/**
* 当前处理
* @return mixed
* @author chendashengpc
*/
public function handler()
{
echo '我是市教育局,我这办不了,你去省教育局' . PHP_EOL;
if ($this->next != null) {
$this->next->handler();
}
}
}
省教育局
代码语言:javascript复制/**
* 省教育局
*/
class ProvincialEducationBureau extends BaseHandler
{
/**
* 下一个请求
* @return mixed
* @author chendashengpc
*/
public function setNext(Handler $handler)
{
$this->next = $handler;
}
/**
* 当前处理
* @return mixed
* @author chendashengpc
*/
public function handler()
{
echo '我是省教育局,我这能办,提交资料就能办了' . PHP_EOL;
}
}
客户端使用
代码语言:javascript复制$county = new CountyEducationBureau();
$municipal = new MunicipalEducationBureau();
$provincial = new ProvincialEducationBureau();
$county->setNext($municipal);
$municipal->setNext($provincial);
$county->handler();
输出
代码语言:javascript复制我是县教育局,我这办不了,你去市教育局
我是市教育局,我这办不了,你去省教育局
我是省教育局,我这能办,提交资料就能办了
UML
优缺点
优点
- 可以控制请求处理的顺序。
- 单一职责原则。可对发起操作和执行操作的类进行解耦。
- 开闭原则。可以在不更改现有代码的情况下在程序中新增处理者。
缺点
- 部分请求可能未被处理。