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

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

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

一、概述

职责链模式(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

相关阅读:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

原文发布于微信公众号 - 决胜机器学习(phpthinker)

原文发表时间:2017-08-28

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java帮帮-微信公众号-技术文章全总结

第二十八天 管家婆家庭记账软件【悟空教程】

本项目为JAVAEE基础班综合项目,包含了若干个知识点,达到将基础班所学知识综合使用,提高了我们对项目的理解与知识点的运用。

1725
来自专栏Python爬虫与算法进阶

Scrapy中如何提高数据的插入速度

速度问题 最近工作中遇到这么一个问题,全站抓取时采用分布式:爬虫A与爬虫B,爬虫A给爬虫B喂饼,爬虫B由于各种原因运行的比较慢,达不到预期效果,所以必须对爬虫...

46711
来自专栏深度学习之tensorflow实战篇

mongodb11天之屠龙宝刀(四)高级查询:MongoDB内嵌字段查询

mongodb11天之获取屠龙宝刀(四)高级查询:MongoDB内嵌字段查询 实战环境 IDE:nosql manager for mongodb 表...

2994
来自专栏日常学python

一步一步教你如何用python操作mysql

这是日常学python的第九篇原创文章 首先祝大家新年快乐哈!学生的估计明天也要上课了,工作的估计早就去上班了,我也快要上课了,哈哈,新年这段时间一直没有写过文...

65913
来自专栏岑玉海

Hive Tuning(一) 连接策略

群里共享了一本hive调优的书记,名叫《Hive Tunning》,就忍不住开始看了,也顺便记录一下自己学到的东西,备忘! 首先,这是hive的数据摘要,别...

3826
来自专栏技术小黑屋

Android修复通知栏跳动的问题

曾经遇到过这样的问题,在我的代码中使用了通知栏,一切都正常,但是就是正在进行的通知栏中属于我的程序的那一条总是上下跳来跳去,一闪一闪的。感觉用户体验很不好,于是...

931
来自专栏WindCoder

网易MySQL微专业学习笔记(四)-实践课数据库对象

这个系列属于个人学习网易云课堂MySQL数据库工程师微专业的相关课程过程中的笔记,本篇为其“MySQL数据库对象与应用”中的MySQL数据类型相关笔记。

721
来自专栏JackieZheng

Java豆瓣电影爬虫——减少与数据库交互实现批量插入

  节前一个误操作把mysql中record表和movie表都清空了,显然我是没有做什么mysql备份的。所以,索性我把所有的表数据都清空的,一夜回到解放前……...

3087
来自专栏烙馅饼喽的技术分享

本人有生以来的第一篇博客,嘿嘿,就发这个吧, 怎样在虚拟主机上使用Castle框架的ActiveRecord

        我在某个私人项目中使用了Castle 的 ActiveRecord.用起来那是真叫个爽,整个项目里楞是一句SQL语句都没有,嘿嘿。超级喜欢上了这...

2685
来自专栏沃趣科技

MySQL的一个表最多可以有多少个字段

问题由来 引用我们客户的原话: *创建如下表,提示我:* ? *如果我将下面表中的varchar(200),修改成text(或blob):报错变为另一个:* ?...

6389

扫码关注云+社区