设计模式专题(二十)——职责链模式
(原创内容,转载请注明来源,谢谢)
一、概述
职责链模式(Chainof Responsibility),是使多个对象都有机会处理请求,从而避免请求的发送者和接收者直接的耦合。将这个对象练成一条链,并且沿着这个链传递该请求,直到有一个对象处理它为止。
客户端发出的请求,如果对于不同的量级、不同的内容,都需要有不同的类进行处理,则可以使用职责链模式。例如员工的请假,不同的请假天数要不同的人来审批;请假的类型不同处理的方式也有所不同。
二、类图
从图中可以看出,由客户端发送请求后,统一发送给handler类,handler类会根据请求的类型(如判断请假的是事假还是病假),发送给不同的具体处理类。处理类如果发现请求的内容超出范围(如请假天数是3天还是10天),则会将请求转发给下一个具体处理类。下一个处理类处理完毕,会将消息直接返回给handler类,由handler返回给客户端。
该模式中,还需要一个默认处理类,将超出一定范围、请求类型不在处理范围的,做一个兼容的处理。
三、实现方式
1、场景
现以请假作为场景,当不同的请假类型、不同的请假天数,假设需要不同的类去进行处理。
由客户端发出请假请求,标明请假类型和天数给统一的handler。
由handler根据类型进行分发给最底层级的各请假类型的处理类,各类再根据具体的请假天数,判断是自己处理还是给高一层级的类进行处理。
2、常量类
为了便于判断不同的请假类型,现设定常量类,用于存放各类请假类型,避免程序中出现请假类型,也让代码更佳优雅。常量类如下:
class LeaveConst{
publicstatic const ANNUAL_LEAVE = 0;
publicstatic const SICK_LEAVE = 1;
publicstatic const COMPASSION_LEAVE = 2;
publicstatic const MARRIAGE_LEAVE = 3;
publicstatic const MATERNITY_LEAVE = 4;
publicstatic const OTHER_LEAVE = 5;
publicstatic const $TypeDef = array(
self::ANNUAL_LEAVE=> '年假',
self::SICK_LEAVE=> '病假',
self::COMPASSION_LEAVE=> '事假',
self::MARRIAGE_LEAVE=>'婚假',
self::MATERNITY_LEAVE=> '产假',
self::OTHER_LEAVE=> '其他'
);
publicstatic const $TypeEnglishDef = array(
0=> 'ANNUAL_LEAVE',
1=> 'SICK_LEAVE',
2=> 'COMPASSION_LEAVE',
3=> 'MARRIAGE_LEAVE',
4=> 'MATERNITY_LEAVE',
5=> 'OTHER_LEAVE'
);
publicstatic const $TypeIn = array(
self::ANNUAL_LEAVE,
self::SICK_LEAVE,
self::COMPASSION_LEAVE,
self::MARRIAGE_LEAVE,
self::MATERNITY_LEAVE,
self::OTHER_LEAVE
);
}
3、Handler处理类
该类起到中间的作用,针对客户端的请求的类型进行任务分发,并返回处理结果。
class Handler{
private$handlerType;
private$type;
private$days;
//设定类型和内容,并自动执行结果
publicfunction setHandler($type, $days){
if(!in_array($type,LeaveConst::$TypeIn) || empty($days) || !is_numeric($days)){
returnfalse;
}
$this->type= $type;
$this->days= $days;
return$this->execute();
}
//执行请求
privatefunction execute(){
//截取出_的前半段,即为类型
$arrType= explode('_', LeaveConst::$TypeEnglishDef($this->type));
//拼接出具体类名
$handlerType= $arrType[0] . 'HandlerA';
//获取具体类的实例
$this->handlerType= $handlerType;
//执行具体类的请求
return$this->handlerType::execute($this->days);
}
}
4、具体的处理类
具体的处理类,通过handler类的分发,进行处理。如果其具备处理能力,则处理后返回结果,否则将对更高层级的处理类发送处理请求。
下面共有三个类。
class AnnualHandlerA{
publicstatic function execute($days){
if(empty($days)|| !is_numeric($days)){
returnfalse;
}
if($days< 3){
/*
小于3时有权限,则直接处理
具体的处理过程
*/
return'处理结果';
}else{
returnAnnualHandlerB::execute($days);
}
}
}
class AnnualHandlerB{
publicstatic function execute($days){
if(empty($days)|| !is_numeric($days) || $days<3){
//如果小于3,不应由该类进行处理,则报错
returnfalse;
}
if($days< 10){
/*
小于10时有权限,则直接处理
...具体的处理过程
*/
return'处理结果';
}else{
returnAnnualHandlerDefault::execute($days);
}
}
}
class AnnualHandlerDefault{
publicstatic function execute($days){
if(empty($days)|| !is_numeric($days) || $days<10){
//如果小于10,不应由该类进行处理,则报错
returnfalse;
}
/*
默认的处理过程,在前面的处理条件都不符合的情况下,
由该类进行处理,实现兼容
...具体的处理过程
*/
return'处理结果';
}
}
5、客户端发送请求
$annualLeave = new Handler();
$annualLeave->setHandler(LeaveConst::ANNUAL_LEAVE, 20);
四、总结
职责链模式,实现请求的统一分发,并且根据不同的请求规模,具体的处理类进行判断和转发,使客户端和请求处理端解耦,也使请求的分发模块和请求的具体实现模块解耦。
该模式下,对请求模式的增删改、对请求规模的增删改,都可以很容易的实现,且不会影响到其他的类。
——written by linhxx 2107.08.28
相关阅读: