「补课」进行时:设计模式(9)——在请假中使用的责任链模式

极客挖掘机 2020-11-11 09:26:05
设计 模式 进行 补课 行时


1. 前文汇总

「补课」进行时:设计模式系列

2. 请假

作为一位新时代的社畜,我们每天起得比鸡早,睡得比狗晚,还时不时的要受到上司的 PUA ,每天都生活在水深火热之中。

生活中总会有各种意外,比如生病了,需要去医院看病,那我们需要请假去医院,一般在公司中,请假的时长和审批领导息息相关,如果这个规则是这样的:

  • 请假 3 天内小组长可以审批
  • 请假 5 天内需要大组长神品
  • 请假 20 天内需要部门经理审批

如果按照顺序思维来写程序的话,那么我们需要做大量的 if...else 的判断,并且所有的类都要耦合在一起,这时,我们可以使用责任链模式,上面的审批流成如下:

我们可以先定义一个员工类:

public interface IPerson {
// 获取当前请假天数
int getDays();
// 获取审批结果
String getResult();
}
public class Person implements IPerson {
private int days;
private String message;
public Person(int days) {
this.days = days;
this.message = "领导,我想请 " + days + " 天假!!!";
}
@Override
public int getDays() {
return this.days;
}
@Override
public String getResult() {
return this.message;
}
}

创建一个抽象 Handler 类:

public abstract class Handler {
public final static int MIN = 3;
public final static int MIDDLE = 5;
public final static int MAX = 20;
// 当前能处理的级别
private int days;
// 责任传递,定义下一个责任人
private Handler nextHandler;
// 所有的类都需要定义自己的能处理的请假天数
public Handler(int days) {
this.days = days;
}
public final void handleMessage(IPerson person) {
if (this.days > person.getDays()) {
this.response(person);
} else {
if (this.nextHandler != null) {
this.nextHandler.handleMessage(person);
} else {
System.out.println("员工想要请假 " + this.days + " 天,超过可以审批的最大权限,那就不批了");
}
}
}
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
protected abstract void response(IPerson person);
}

这个类中最核心的部分是定义了 nextHandler 下一个责任人,如果当前的员工请假的请求不属于自己的审批范畴,则会将这个请求转发至下一个审批人。

接下来是三位具体的审批人:

public class Leader1 extends Handler {
// 小组长
public Leader1() {
super(Handler.MIN);
}
@Override
protected void response(IPerson person) {
System.out.println("-----------向小组长请示------------");
System.out.println(person.getResult());
System.out.println("-----------请示通过---------------");
}
}
public class Leader2 extends Handler {
// 大组长
public Leader2() {
super(Handler.MIDDLE);
}
@Override
protected void response(IPerson person) {
System.out.println("-----------向大组长请示------------");
System.out.println(person.getResult());
System.out.println("-----------请示通过---------------");
}
}
public class Leader3 extends Handler {
// 部门经理
public Leader3() {
super(Handler.MAX);
}
@Override
protected void response(IPerson person) {
System.out.println("-----------向部门经理请示--------------");
System.out.println(person.getResult());
System.out.println("-----------请示通过---------------");
}
}

然后我们来写一个测试类:

public class Test {
public static void main(String[] args) {
Random random = new Random();
ArrayList<IPerson> personList = new ArrayList<>();
for (int i = 0; i < 5; i++) {
personList.add(new Person(random.nextInt(30)));
}
Handler leader1 = new Leader1();
Handler leader2 = new Leader2();
Handler leader3 = new Leader3();
leader1.setNextHandler(leader2);
leader2.setNextHandler(leader3);
for (IPerson person: personList) {
leader1.handleMessage(person);
}
}
}

执行结果如下:

-----------向部门经理请示--------------
领导,我想请 17 天假!!!
-----------请示通过---------------
员工想要请假 20 天,超过可以审批的最大权限,那就不批了
-----------向小组长请示------------
领导,我想请 0 天假!!!
-----------请示通过---------------
-----------向部门经理请示--------------
领导,我想请 11 天假!!!
-----------请示通过---------------
-----------向大组长请示------------
领导,我想请 4 天假!!!
-----------请示通过---------------

3. 责任链模式

责任链模式定义如下:

Avoid coupling the sender of a request to its receiver by giving more thanone object a chance to handle the request.Chain the receiving objects andpass the request along the chain until an object handles it.(使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。)

责任链模式的重点是在 「链」 上,由一条链去处理相似的请求在链中决定谁来处理这个请求,并返回相应的结果,这个链类似于一个单向链表的数据结构,从开始一直向后迭代,知道找不到下一个为止,它的通用类图如下:

通用代码如下:

3.1 抽象 Handler

public abstract class Handler {
private Handler nextHandler;
// 每个处理者都必须对请求作出处理
public final Response handleMessage(Request request) {
Response response = null;
// 判断当前处理级别
if (this.getHandlerLevel().equals(request.getLevel())) {
response = this.echo(request);
} else {
// 判断是否有下一个处理者
if (this.nextHandler != null) {
response = this.nextHandler.handleMessage(request);
} else {
// 没有匹配的业务处理者,逻辑根据具体场景实现
}
}
return response;
}
// 设置下一个处理者
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
protected abstract Level getHandlerLevel();
protected abstract Response echo(Request request);
}

抽象的处理者实现三个职责:

  • 定义一个请求的处理方法 handleMessage ,唯一对外开放的方法。
  • 定义一个链的编排方法 setNext ,设置下一个处理者。
  • 定义了具体的请求者必须实现的两个方法:定义自己能够处理的级别 getHandlerLevel 和具体的处理任务 echo 。

3.2 具体处理者

public class ConcreteHandler1 extends Handler {
@Override
protected Level getHandlerLevel() {
// 设置自己的处理级别
return null;
}
@Override
protected Response echo(Request request) {
// 设置处理的业务功能
return null;
}
}
public class ConcreteHandler2 extends Handler {
@Override
protected Level getHandlerLevel() {
return null;
}
@Override
protected Response echo(Request request) {
return null;
}
}
public class ConcreteHandler3 extends Handler {
@Override
protected Level getHandlerLevel() {
return null;
}
@Override
protected Response echo(Request request) {
return null;
}
}

定义三个具体的处理者,以便组成一个链。

3.3 其余相关代码

public class Level {
}
public class Request {
public Level getLevel() {
return null;
}
}
public class Response {
}

3.4 测试类

最后是一个测试类:

public class Test {
public static void main(String[] args) {
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
Handler handler3 = new ConcreteHandler3();
handler1.setNextHandler(handler2);
handler2.setNextHandler(handler3);
Response response = handler1.handleMessage(new Request());
}
}

在实际的使用过程中,最后都会有一个封装类对责任链模式进行封装,用来取代我们现在的这个测试类,直接返回链中的第一个处理者,具体链的设置不需要高层次模块关系,这样,更简化了高层次模块的调用,减少模块间的耦合,提高系统的灵活性。

4. 优点

任链模式非常显著的优点是将请求和处理分开。请求者可以不用知道是谁处理的,处理者可以不用知道请求的全貌(例如在 J2EE 项目开发中,可以剥离出无状态 Bean 由责任链处理),两者解耦,提高系统的灵活性。

5. 缺点

责任链有两个非常显著的缺点:

  • 性能问题,每个请求都是从链头遍历到链尾,特别是在链比较长的时候,性能是一个非常大的问题。
  • 调试不很方便,特别是链条比较长,环节比较多的时候,由于采用了类似递归的方式,调试的时候逻辑可能比较复杂。
版权声明
本文为[极客挖掘机]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/babycomeon/p/13956971.html

  1. 【计算机网络 12(1),尚学堂马士兵Java视频教程
  2. 【程序猿历程,史上最全的Java面试题集锦在这里
  3. 【程序猿历程(1),Javaweb视频教程百度云
  4. Notes on MySQL 45 lectures (1-7)
  5. [computer network 12 (1), Shang Xuetang Ma soldier java video tutorial
  6. The most complete collection of Java interview questions in history is here
  7. [process of program ape (1), JavaWeb video tutorial, baidu cloud
  8. Notes on MySQL 45 lectures (1-7)
  9. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  10. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  11. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  12. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  13. 【递归,Java传智播客笔记
  14. [recursion, Java intelligence podcast notes
  15. [adhere to painting for 386 days] the beginning of spring of 24 solar terms
  16. K8S系列第八篇(Service、EndPoints以及高可用kubeadm部署)
  17. K8s Series Part 8 (service, endpoints and high availability kubeadm deployment)
  18. 【重识 HTML (3),350道Java面试真题分享
  19. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  20. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  21. [re recognize HTML (3) and share 350 real Java interview questions
  22. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  23. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  24. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  25. RPC 1: how to develop RPC framework from scratch
  26. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  27. RPC 1: how to develop RPC framework from scratch
  28. 一次性捋清楚吧,对乱糟糟的,Spring事务扩展机制
  29. 一文彻底弄懂如何选择抽象类还是接口,连续四年百度Java岗必问面试题
  30. Redis常用命令
  31. 一双拖鞋引发的血案,狂神说Java系列笔记
  32. 一、mysql基础安装
  33. 一位程序员的独白:尽管我一生坎坷,Java框架面试基础
  34. Clear it all at once. For the messy, spring transaction extension mechanism
  35. A thorough understanding of how to choose abstract classes or interfaces, baidu Java post must ask interview questions for four consecutive years
  36. Redis common commands
  37. A pair of slippers triggered the murder, crazy God said java series notes
  38. 1、 MySQL basic installation
  39. Monologue of a programmer: despite my ups and downs in my life, Java framework is the foundation of interview
  40. 【大厂面试】三面三问Spring循环依赖,请一定要把这篇看完(建议收藏)
  41. 一线互联网企业中,springboot入门项目
  42. 一篇文带你入门SSM框架Spring开发,帮你快速拿Offer
  43. 【面试资料】Java全集、微服务、大数据、数据结构与算法、机器学习知识最全总结,283页pdf
  44. 【leetcode刷题】24.数组中重复的数字——Java版
  45. 【leetcode刷题】23.对称二叉树——Java版
  46. 【leetcode刷题】22.二叉树的中序遍历——Java版
  47. 【leetcode刷题】21.三数之和——Java版
  48. 【leetcode刷题】20.最长回文子串——Java版
  49. 【leetcode刷题】19.回文链表——Java版
  50. 【leetcode刷题】18.反转链表——Java版
  51. 【leetcode刷题】17.相交链表——Java&python版
  52. 【leetcode刷题】16.环形链表——Java版
  53. 【leetcode刷题】15.汉明距离——Java版
  54. 【leetcode刷题】14.找到所有数组中消失的数字——Java版
  55. 【leetcode刷题】13.比特位计数——Java版
  56. oracle控制用户权限命令
  57. 三年Java开发,继阿里,鲁班二期Java架构师
  58. Oracle必须要启动的服务
  59. 万字长文!深入剖析HashMap,Java基础笔试题大全带答案
  60. 一问Kafka就心慌?我却凭着这份,图灵学院vip课程百度云