前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式专题(二十) ——职责链模式

设计模式专题(二十) ——职责链模式

作者头像
用户1327360
发布2018-03-07 11:52:46
6200
发布2018-03-07 11:52:46
举报
文章被收录于专栏:决胜机器学习决胜机器学习

设计模式专题(二十)——职责链模式

(原创内容,转载请注明来源,谢谢)

一、概述

职责链模式(Chainof Responsibility),是使多个对象都有机会处理请求,从而避免请求的发送者和接收者直接的耦合。将这个对象练成一条链,并且沿着这个链传递该请求,直到有一个对象处理它为止。

客户端发出的请求,如果对于不同的量级、不同的内容,都需要有不同的类进行处理,则可以使用职责链模式。例如员工的请假,不同的请假天数要不同的人来审批;请假的类型不同处理的方式也有所不同。

二、类图

从图中可以看出,由客户端发送请求后,统一发送给handler类,handler类会根据请求的类型(如判断请假的是事假还是病假),发送给不同的具体处理类。处理类如果发现请求的内容超出范围(如请假天数是3天还是10天),则会将请求转发给下一个具体处理类。下一个处理类处理完毕,会将消息直接返回给handler类,由handler返回给客户端。

该模式中,还需要一个默认处理类,将超出一定范围、请求类型不在处理范围的,做一个兼容的处理。

三、实现方式

1、场景

现以请假作为场景,当不同的请假类型、不同的请假天数,假设需要不同的类去进行处理。

由客户端发出请假请求,标明请假类型和天数给统一的handler。

由handler根据类型进行分发给最底层级的各请假类型的处理类,各类再根据具体的请假天数,判断是自己处理还是给高一层级的类进行处理。

2、常量类

为了便于判断不同的请假类型,现设定常量类,用于存放各类请假类型,避免程序中出现请假类型,也让代码更佳优雅。常量类如下:

代码语言:javascript
复制
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处理类

该类起到中间的作用,针对客户端的请求的类型进行任务分发,并返回处理结果。

代码语言:javascript
复制
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类的分发,进行处理。如果其具备处理能力,则处理后返回结果,否则将对更高层级的处理类发送处理请求。

下面共有三个类。

代码语言:javascript
复制
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、客户端发送请求

代码语言:javascript
复制
$annualLeave = new Handler();
$annualLeave->setHandler(LeaveConst::ANNUAL_LEAVE, 20);

四、总结

职责链模式,实现请求的统一分发,并且根据不同的请求规模,具体的处理类进行判断和转发,使客户端和请求处理端解耦,也使请求的分发模块和请求的具体实现模块解耦。

该模式下,对请求模式的增删改、对请求规模的增删改,都可以很容易的实现,且不会影响到其他的类。

——written by linhxx 2107.08.28

相关阅读:

设计模式专题(十九) ——命令模式

设计模式专题(十八) ——桥接模式

设计模式专题(十七) ——单例模式

设计模式专题(十六)——迭代器模式

设计模式专题(十五) ——组合模式

设计模式专题(十四)——适配器模式

设计模式专题(十三) ——备忘录模式

设计模式专题(十二)——状态模式

设计模式专题(十一)——抽象工厂模式

设计模式专题(十)——观察者模式

设计模式专题(九) ——外观模式

设计模式专题(八) ——模板方法模式

设计模式专题(七)——建造者模式

设计模式专题(六)——原型模式

设计模式专题(五)——工厂方法模式

设计模式专题(四)——代理模式

设计模式专题(三)——装饰模式

设计模式专题(二)——策略模式

设计模式专题(一)——面向对象的设计原则

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-08-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 决胜机器学习 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 设计模式专题(十九) ——命令模式
  • 设计模式专题(十八) ——桥接模式
  • 设计模式专题(十七) ——单例模式
  • 设计模式专题(十六)——迭代器模式
  • 设计模式专题(十五) ——组合模式
  • 设计模式专题(十四)——适配器模式
  • 设计模式专题(十三) ——备忘录模式
  • 设计模式专题(十二)——状态模式
  • 设计模式专题(十一)——抽象工厂模式
  • 设计模式专题(十)——观察者模式
  • 设计模式专题(九) ——外观模式
  • 设计模式专题(八) ——模板方法模式
  • 设计模式专题(七)——建造者模式
  • 设计模式专题(六)——原型模式
  • 设计模式专题(五)——工厂方法模式
  • 设计模式专题(四)——代理模式
  • 设计模式专题(三)——装饰模式
  • 设计模式专题(二)——策略模式
  • 设计模式专题(一)——面向对象的设计原则
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档