请求的链式处理——职责链模式(三)

16.3 完整解决方案 为了让采购单的审批流程更加灵活,并实现采购单的链式传递和处理,Sunny公司开发人员使用职责链模式来实现采购单的分级审批,其基本结构如图16-3所示:

请求的链式处理——职责链模式(三) - 图1

在图16-3中,抽象类Approver充当抽象处理者(抽象传递者),Director、VicePresident、President和Congress充当具体处理者(具体传递者),PurchaseRequest充当请求类。完整代码如下所示:

  1. //采购单:请求类
  2. class PurchaseRequest {
  3. private double amount; //采购金额
  4. private int number; //采购单编号
  5. private String purpose; //采购目的
  6. public PurchaseRequest(double amount, int number, String purpose) {
  7. this.amount = amount;
  8. this.number = number;
  9. this.purpose = purpose;
  10. }
  11. public void setAmount(double amount) {
  12. this.amount = amount;
  13. }
  14. public double getAmount() {
  15. return this.amount;
  16. }
  17. public void setNumber(int number) {
  18. this.number = number;
  19. }
  20. public int getNumber() {
  21. return this.number;
  22. }
  23. public void setPurpose(String purpose) {
  24. this.purpose = purpose;
  25. }
  26. public String getPurpose() {
  27. return this.purpose;
  28. }
  29. }
  30. //审批者类:抽象处理者
  31. abstract class Approver {
  32. protected Approver successor; //定义后继对象
  33. protected String name; //审批者姓名
  34. public Approver(String name) {
  35. this.name = name;
  36. }
  37. //设置后继者
  38. public void setSuccessor(Approver successor) {
  39. this.successor = successor;
  40. }
  41. //抽象请求处理方法
  42. public abstract void processRequest(PurchaseRequest request);
  43. }
  44. //主任类:具体处理者
  45. class Director extends Approver {
  46. public Director(String name) {
  47. super(name);
  48. }
  49. //具体请求处理方法
  50. public void processRequest(PurchaseRequest request) {
  51. if (request.getAmount() < 50000) {
  52. System.out.println("主任" + this.name + "审批采购单:" + request.getNumber() + ",金额:" + request.getAmount() + "元,采购目的:" + request.getPurpose() + "。"); //处理请求
  53. }
  54. else {
  55. this.successor.processRequest(request); //转发请求
  56. }
  57. }
  58. }
  59. //副董事长类:具体处理者
  60. class VicePresident extends Approver {
  61. public VicePresident(String name) {
  62. super(name);
  63. }
  64. //具体请求处理方法
  65. public void processRequest(PurchaseRequest request) {
  66. if (request.getAmount() < 100000) {
  67. System.out.println("副董事长" + this.name + "审批采购单:" + request.getNumber() + ",金额:" + request.getAmount() + "元,采购目的:" + request.getPurpose() + "。"); //处理请求
  68. }
  69. else {
  70. this.successor.processRequest(request); //转发请求
  71. }
  72. }
  73. }
  74. //董事长类:具体处理者
  75. class President extends Approver {
  76. public President(String name) {
  77. super(name);
  78. }
  79. //具体请求处理方法
  80. public void processRequest(PurchaseRequest request) {
  81. if (request.getAmount() < 500000) {
  82. System.out.println("董事长" + this.name + "审批采购单:" + request.getNumber() + ",金额:" + request.getAmount() + "元,采购目的:" + request.getPurpose() + "。"); //处理请求
  83. }
  84. else {
  85. this.successor.processRequest(request); //转发请求
  86. }
  87. }
  88. }
  89. //董事会类:具体处理者
  90. class Congress extends Approver {
  91. public Congress(String name) {
  92. super(name);
  93. }
  94. //具体请求处理方法
  95. public void processRequest(PurchaseRequest request) {
  96. System.out.println("召开董事会审批采购单:" + request.getNumber() + ",金额:" + request.getAmount() + "元,采购目的:" + request.getPurpose() + "。"); //处理请求
  97. }
  98. }

编写如下客户端测试代码:

  1. class Client {
  2. public static void main(String[] args) {
  3. Approver wjzhang,gyang,jguo,meeting;
  4. wjzhang = new Director("张无忌");
  5. gyang = new VicePresident("杨过");
  6. jguo = new President("郭靖");
  7. meeting = new Congress("董事会");
  8. //创建职责链
  9. wjzhang.setSuccessor(gyang);
  10. gyang.setSuccessor(jguo);
  11. jguo.setSuccessor(meeting);
  12. //创建采购单
  13. PurchaseRequest pr1 = new PurchaseRequest(45000,10001,"购买倚天剑");
  14. wjzhang.processRequest(pr1);
  15. PurchaseRequest pr2 = new PurchaseRequest(60000,10002,"购买《葵花宝典》");
  16. wjzhang.processRequest(pr2);
  17. PurchaseRequest pr3 = new PurchaseRequest(160000,10003,"购买《金刚经》");
  18. wjzhang.processRequest(pr3);
  19. PurchaseRequest pr4 = new PurchaseRequest(800000,10004,"购买桃花岛");
  20. wjzhang.processRequest(pr4);
  21. }
  22. }

编译并运行程序,输出结果如下:

  1. 主任张无忌审批采购单:10001,金额:45000.0元,采购目的:购买倚天剑。
  2. 副董事长杨过审批采购单:10002,金额:60000.0元,采购目的:购买《葵花宝典》。
  3. 董事长郭靖审批采购单:10003,金额:160000.0元,采购目的:购买《金刚经》。
  4. 召开董事会审批采购单:10004,金额:800000.0元,采购目的:购买桃花岛。

如果需要在系统增加一个新的具体处理者,如增加一个经理(Manager)角色可以审批5万元至8万元(不包括8万元)的采购单,需要编写一个新的具体处理者类Manager,作为抽象处理者类Approver的子类,实现在Approver类中定义的抽象处理方法,如果采购金额大于等于8万元,则将请求转发给下家,代码如下所示:

  1. //经理类:具体处理者
  2. class Manager extends Approver {
  3. public Manager(String name) {
  4. super(name);
  5. }
  6. //具体请求处理方法
  7. public void processRequest(PurchaseRequest request) {
  8. if (request.getAmount() < 80000) {
  9. System.out.println("经理" + this.name + "审批采购单:" + request.getNumber() + ",金额:" + request.getAmount() + "元,采购目的:" + request.getPurpose() + "。"); //处理请求
  10. }
  11. else {
  12. this.successor.processRequest(request); //转发请求
  13. }
  14. }
  15. }

由于链的创建过程由客户端负责,因此增加新的具体处理者类对原有类库无任何影响,无须修改已有类的源代码,符合“开闭原则”。

在客户端代码中,如果要将新的具体请求处理者应用在系统中,需要创建新的具体处理者对象,然后将该对象加入职责链中。如在客户端测试代码中增加如下代码:

  1. Approver rhuang;
  2. rhuang = new Manager("黄蓉");

将建链代码改为:

  1. //创建职责链

wjzhang.setSuccessor(rhuang); //将“黄蓉”作为“张无忌”的下家
rhuang.setSuccessor(gyang); //将“杨过”作为“黄蓉”的下家
gyang.setSuccessor(jguo);
jguo.setSuccessor(meeting);

  1. 重新编译并运行程序,输出结果如下:

主任张无忌审批采购单:10001,金额:45000.0元,采购目的:购买倚天剑。 经理黄蓉审批采购单:10002,金额:60000.0元,采购目的:购买《葵花宝典》。 董事长郭靖审批采购单:10003,金额:160000.0元,采购目的:购买《金刚经》。 召开董事会审批采购单:10004,金额:800000.0元,采购目的:购买桃花岛。 ```

思考

如果将审批流程由“主任—>副董事长—>董事长—>董事会”调整为“主任—>董事长—>董事会”,系统将做出哪些改动?预测修改之后客户端代码的输出结果。