模式说明

工作中可能有这样的请求处理场景,例如假期审批,会根据申请假期的天数长短,由不同权限的主管者审批,但提交申请时总是提交给自己的直接主管,由直接主管来判断是否需要上升到更高权限的管理者来审批。类似场景可以描述为一个请求根据其内容由不同级别的处理者处理,申请入口总是最低级别的处理者。在客户端中处理此类请求,最简单直接的做法用if-else语句遍询所有处理者,最终总能够被某一权限的处理者处理。这种做法的缺点是客户端责任太大,违背了单一职责原则,另外可扩展性也很差,当需要修改或删减处理者时,需要修改客户端代码。对于这种场景可以使用责任链模式实现,创建每一层级的处理者类,内部均实现一个处理方法,请求从最底层处理者开始,每一层级处理者处理请求时,如判断不在权限范围内,则向后继处理者传递该请求,直至最后一层。这种做法很好地实践了单一职责原则,由于每一层级处理者均为一类,对处理者的变化也有良好的扩展能力。

本示例以假期申请为例,演示不同天数的申请如何通过责任链传递从最低层级管理者传递到具有相应权限的管理者处并得到处理。

结构

抽象处理者类:
处理请求的对象,类内实现一个设置后继处理者的普通方法,定义一个处理请求的抽象方法。
具体处理者类
继承抽象处理者类,实现抽象方法。
请求类(可选)
当请求比较复杂时,可以将其封装成类。当请求比较简单,如申请假期的场景,可以只用int表示请求。

代码演示

  1. package com.yukiyama.pattern.behavior;
  2. /**
  3. * 责任链模式
  4. */
  5. public class ResponsibilityChainDemo {
  6. public static void main(String[] args) {
  7. // 声明责任链上所有级别的处理者
  8. // L1处理者有小于3天的请假审批权
  9. Manager L1 = new L1Manager("一级主管");
  10. // L2处理者有3到10天的请假审批权
  11. Manager L2 = new L2Manager("二级主管");
  12. // L3处理者有20天以内的请假审批权,超过则驳回
  13. Manager L3 = new L3Manager("三级主管");
  14. // 从低到高,每个层级的处理者设置自己的上级(后继)处理者
  15. // 使请求能够从最低级处理者开始传递到最高级处理者
  16. L1.setSuperior(L2);
  17. L2.setSuperior(L3);
  18. // 声明一个请求并设置请求的内容
  19. Application app = new Application();
  20. app.setDaysNum(2);
  21. // 每次申请均只需由最低级处理者一级主管L1来执行申请
  22. // 输出"一级主管批准2天请假申请。"
  23. L1.apply(app);
  24. app.setDaysNum(5);
  25. // 输出“二级主管批准5天请假申请。”
  26. L1.apply(app);
  27. app.setDaysNum(15);
  28. // 输出“三级主管批准15天请假申请。”
  29. L1.apply(app);
  30. app.setDaysNum(21);
  31. // 输出“该请假申请天数为21天,三级主管驳回超过20天假期申请。”
  32. L1.apply(app);
  33. }
  34. }
  35. /**
  36. * 抽象处理者类
  37. * 持有一个name属性,并在有参构造器中初始化该属性。持有自己的后继处理者
  38. * superior,通过普通方法setSuperior设置。定义了一个处理申请的抽象
  39. * 方法apply(Application app)。
  40. */
  41. abstract class Manager{
  42. protected String name;
  43. protected Manager superior;
  44. public Manager(String name) {
  45. this.name = name;
  46. }
  47. public void setSuperior(Manager superior) {
  48. this.superior = superior;
  49. }
  50. public abstract void apply(Application app);
  51. }
  52. /**
  53. * 具体处理者类
  54. * 继承抽象处理者类,实现了抽象方法apply,根据申请内容的不同,不能处理时
  55. * 调用后继处理者的apply方法交由后继处理者处理。
  56. * 下例是最低级别的处理者L1。
  57. */
  58. class L1Manager extends Manager{
  59. public L1Manager(String name) {
  60. super(name);
  61. }
  62. @Override
  63. public void apply(Application app) {
  64. if(app.getDaysNum() < 3) {
  65. System.out.printf("%s批准%d天请假申请。\n", name, app.getDaysNum());
  66. } else {
  67. if(superior != null) {
  68. superior.apply(app);
  69. }
  70. }
  71. }
  72. }
  73. /**
  74. * 具体处理者类
  75. * 下例是L1的后继处理者L2。
  76. */
  77. class L2Manager extends Manager{
  78. public L2Manager(String name) {
  79. super(name);
  80. }
  81. @Override
  82. public void apply(Application app) {
  83. if(app.getDaysNum() >= 3 && app.getDaysNum() <= 10) {
  84. System.out.printf("%s批准%d天请假申请。\n", name, app.getDaysNum());
  85. } else {
  86. if(superior != null) {
  87. superior.apply(app);
  88. }
  89. }
  90. }
  91. }
  92. /**
  93. * 具体处理者类
  94. * 下例是L2的后继处理者L3。
  95. */
  96. class L3Manager extends Manager{
  97. public L3Manager(String name) {
  98. super(name);
  99. }
  100. @Override
  101. public void apply(Application app) {
  102. if(app.getDaysNum() > 10 && app.getDaysNum() <= 20) {
  103. System.out.printf("%s批准%d天请假申请。\n", name, app.getDaysNum());
  104. } else {
  105. System.out.printf("该请假申请天数为%d天,%s驳回超过20天假期申请。\n", app.getDaysNum(), name);
  106. }
  107. }
  108. }
  109. /**
  110. * 请求类(可选)
  111. * 当请求包含较多属性时,可以将请求封装成类。当请求比较简单如申请放假天数,
  112. * 也可以只用基本数据类型。
  113. */
  114. class Application{
  115. private int daysNum;
  116. public int getDaysNum() {
  117. return daysNum;
  118. }
  119. public void setDaysNum(int daysNum) {
  120. this.daysNum = daysNum;
  121. }
  122. }