责任链模式

1.模式的定义与特点

责任链模式的定义:为了避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连城一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。

责任链模式也叫职责链模式

在责任链模式中,客户只需要将请求发送到责任链上即可,无需关心请求的处理细节和请求的传递过程,请求会自动进行传递。所以责任链将请求的发送者和请求的处理者解耦了。

优点

  1. 降低了对象之间的耦合度。该模式使得一个对象无需知道到底是哪一个对象处理其请求以及链的结构,发送者和接收者也无须拥有对象的明确信息。
  2. 增强了系统的可扩展性。可以根据需要增加新的请求处理类,满足开闭原则
  3. 增强了给对象指派职责的灵活性。当工作流程发生变化,可以动态的改变链内的成员或者调动他们的次序,也可动态的新增或者删除责任。
  4. 责任链简化了对象之间的连接。每个对象只需保持一个指向其后继者的引用,不需要保持其他所有处理者的引用,这避免了使用众多的if或者if-else语句。
  5. 责任分担。每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。

缺点

  1. 不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
  2. 对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
  3. 职责链建立的合理性要求要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。

2.模式的结构与实现

通常情况下,可以通过数据链表来实现职责链模式的数据结构。

1.模式的结构

责任链模式主要包含以下角色:

  1. 抽象处理者角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
  2. 具体处理者角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将请求传给它的后继者。
  3. 客户类角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。

责任链模式的本质是解耦请求与处理,让请求在处理链中能进行传递与被处理;理解责任链模式应当理解其模式,而不是其具体实现。责任链模式的独到之处是将其节点处理组合成了链式结构,并允许节点自身决定是否进行请求处理或转发,相当于让请求流动起来。

2.模式的实现

  1. /**
  2. * @author liyuan
  3. * @date 2021年07月13日 13:33
  4. * 抽象处理者角色
  5. */
  6. public abstract class Handler {
  7. private Handler next;
  8. public void setNext(Handler next) {
  9. this.next = next;
  10. }
  11. public Handler getNext() {
  12. return next;
  13. }
  14. //处理请求的方法
  15. public abstract void handleRequest(String request);
  16. }
  17. /**
  18. * @author liyuan
  19. * @date 2021年07月13日 13:34
  20. * 具体处理角色1
  21. */
  22. public class ConcreteHandler1 extends Handler{
  23. @Override
  24. public void handleRequest(String request) {
  25. if (request.equals("one")) {
  26. System.out.println("具体处理者1负责处理该请求!");
  27. } else {
  28. if (getNext() != null) {
  29. getNext().handleRequest(request);
  30. } else {
  31. System.out.println("没有人处理该请求!");
  32. }
  33. }
  34. }
  35. }
  36. /**
  37. * @author liyuan
  38. * @date 2021年07月13日 13:34
  39. * 具体处理角色1
  40. */
  41. public class ConcreteHandler2 extends Handler{
  42. @Override
  43. public void handleRequest(String request) {
  44. if (request.equals("two")) {
  45. System.out.println("具体处理者2负责处理该请求!");
  46. } else {
  47. if (getNext() != null) {
  48. getNext().handleRequest(request);
  49. } else {
  50. System.out.println("没有人处理该请求!");
  51. }
  52. }
  53. }
  54. }
  55. /**
  56. * @author liyuan
  57. * @date 2021年07月13日 13:36
  58. */
  59. public class Test {
  60. public static void main(String[] args) {
  61. Handler handler1 = new ConcreteHandler1();
  62. Handler handler2 = new ConcreteHandler2();
  63. handler1.setNext(handler2);
  64. handler1.handleRequest("two");
  65. }
  66. }

程序执行结果如下

  1. 具体处理者2负责处理该请求!

在上面代码中,我们把消息硬编码为 String 类型,而在真实业务中,消息是具备多样性的,可以是 int、String 或者自定义类型。因此,在上面代码的基础上,可以对消息类型进行抽象 Request,增强了消息的兼容性。

3.模式的应用实例

【例】用责任链模式设计一个请假条审批模块。

分析:假如规定学生请假小于或等于 2 天,班主任可以批准;小于或等于 7 天,系主任可以批准;小于或等于 10 天,院长可以批准;其他情况不予批准;这个实例适合使用职责链模式实现。

首先,定义一个领导类(Leader),它是抽象处理者,包含了一个指向下一位领导的指针 next 和一个处理假条的抽象处理方法 handleRequest(int LeaveDays);然后,定义班主任类(ClassAdviser)、系主任类(DepartmentHead)和院长类(Dean),它们是抽象处理者的子类,是具体处理者,必须根据自己的权力去实现父类的 handleRequest(int LeaveDays) 方法,如果无权处理就将假条交给下一位具体处理者,直到最后;客户类负责创建处理链,并将假条交给链头的具体处理者(班主任)。图 3 所示是其结构图。

  1. /**
  2. * @author liyuan
  3. * @date 2021年07月13日 15:44
  4. */
  5. public abstract class Leader {
  6. private Leader next;
  7. public void setNext(Leader next){
  8. this.next = next;
  9. }
  10. public Leader getNext(){
  11. return next;
  12. }
  13. public abstract void handleRequest(int leaveDay);
  14. }
  15. /**
  16. * @author liyuan
  17. * @date 2021年07月13日 15:54
  18. * 具体处理者1:班主任类
  19. */
  20. public class ClassAdviser extends Leader {
  21. @Override
  22. public void handleRequest(int leaveDay) {
  23. if (leaveDay <= 2) {
  24. System.out.println("班主任批准您请假" + leaveDay + "天。");
  25. } else {
  26. if (getNext() != null) {
  27. getNext().handleRequest(leaveDay);
  28. } else {
  29. System.out.println("请假天数太多,没有人批准该假条!");
  30. }
  31. }
  32. }
  33. }
  34. /**
  35. * @author liyuan
  36. * @date 2021年07月13日 15:55
  37. */
  38. public class DepartmentHead extends Leader{
  39. @Override
  40. public void handleRequest(int leaveDay) {
  41. if (leaveDay <= 7) {
  42. System.out.println("系主任批准您请假" + leaveDay + "天。");
  43. } else {
  44. if (getNext() != null) {
  45. getNext().handleRequest(leaveDay);
  46. } else {
  47. System.out.println("请假天数太多,没有人批准该假条!");
  48. }
  49. }
  50. }
  51. }
  52. /**
  53. * @author liyuan
  54. * @date 2021年07月13日 15:57
  55. * 具体处理者4:教务处长类
  56. */
  57. public class DeanOfStudies extends Leader{
  58. @Override
  59. public void handleRequest(int leaveDay) {
  60. if (leaveDay <= 20) {
  61. System.out.println("教务处长批准您请假" + leaveDay + "天。");
  62. } else {
  63. if (getNext() != null) {
  64. getNext().handleRequest(leaveDay);
  65. } else {
  66. System.out.println("请假天数太多,没有人批准该假条!");
  67. }
  68. }
  69. }
  70. }
  71. /**
  72. * @author liyuan
  73. * @date 2021年07月13日 15:55
  74. */
  75. public class DepartmentHead extends Leader{
  76. @Override
  77. public void handleRequest(int leaveDay) {
  78. if (leaveDay <= 7) {
  79. System.out.println("系主任批准您请假" + leaveDay + "天。");
  80. } else {
  81. if (getNext() != null) {
  82. getNext().handleRequest(leaveDay);
  83. } else {
  84. System.out.println("请假天数太多,没有人批准该假条!");
  85. }
  86. }
  87. }
  88. }
  89. /**
  90. * @author liyuan
  91. * @date 2021年07月13日 15:58
  92. */
  93. public class Test {
  94. public static void main(String[] args) {
  95. //组装责任链
  96. Leader teacher1 = new ClassAdviser();
  97. Leader teacher2 = new DepartmentHead();
  98. Leader teacher3 = new Dean();
  99. Leader teacher4=new DeanOfStudies();
  100. teacher1.setNext(teacher2);
  101. teacher2.setNext(teacher3);
  102. teacher3.setNext(teacher4);
  103. //提交请求
  104. teacher1.handleRequest(30);
  105. }
  106. }

执行结果如下:

请假天数太多,没有人批准该假条!

3.模式的应用场景

  1. 多个对象可以处理一个请求,但具体由哪个对象处理该请求在运行时自动确定。
  2. 可动态制定一组对象处理请求,或添加新的处理者。
  3. 需要在不明确制定请求处理者的情况下,向多个处理者中的一个提交请求。

4.模式的扩展

责任链模式存在以下两种情况

  1. 纯的责任链模式:一个请求必须被某一个处理者对象所接受,且一个具体处理者对某个请求的处理只能采用以下两种行为之一

    • 自己处理(承担责任)
    • 把责任推个下家处理。
  2. 不纯的责任链模式:允许出现某一个具体处理者对象在承担了请求的一部分责任后又将剩余的责任传给下家的情况,且一个请求可以最终不被任何接收端对象所接收。