场景引入:在很多情况下可以处理某个请求的对象并不止一个,例如大学里的奖学金审批,学生在向班主任提交审批表之后首先是班主任签字,然后交给学院负责人审核签字,最后交由学工处负责人审批。在这个过程中奖学金申请表可以看成一个请求对象,而不同级别的审批者都可以处理该请求对象,除了辅导员之外,学生不需要一一与其它审批者交互,只需等待结果就好。在审批的过程中如果有一个审批者认为不符合条件,则终止请求,否则将请求递交给下一个审批者审批,最终有学工处负责人确定是否授予奖学金。
奖学金审批示意图
在上图中,班主任,学院负责人,学工处负责人都可以处理奖学金申请表,它们构成一个处理申请表的链式结果,申请表沿着这条长链进行传递,这条链就称为责任链。
定义:避免将一个请求的发送者与接受者耦合在一起,让多个对象都有机会处理请求。将接收请求的对象连接成一条链,并且沿着这条链传递请求,直到有一个对象能够处理它为止。
由上图可知,职责链包含两个角色:
(1) Handler(抽象处理者):它定义了一个请求的接口,一般设计为抽象类,由于不同的具体处理者处理请求的方式不同,因此在其中定义了抽象请求处理方法。每一个处理者的下家还是一个处理者,故在抽象处理者中定义一个抽象处理者类型的对象作为对下家的引用,通过该引用处理者可以连成一条链。
(2) ConcreteHandle(具体处理者):它是抽象处理者的子类,可以处理用户请求,在具体处理者类中实现了抽象处理者中定义的抽象请求处理方法,在处理请求之前要判断,看是否有相应的处理权限,如果可以处理请求就处理,否则就将它转发给后继者;在具体处理者中可以访问链中的下一个对象,以便请求的转发。
职责链模式应用实例
1. 实例说明
某企业的SCM(供应链管理)系统中包含一个采购审批子系统。该企业的采购审批是分级进行的,即根据采购金额的不同由不同层次的主管人员来审批。
主任可以审批5万元以下的(不包括5万元)的采购单,副董事长可以审批5万元至10万元(不包括10万元)的采购单,董事长可以审批10万至50万(不包括50万)的采购单,50万及以上的采购单则需要开董事会讨论决定,如下图所示。
2. 实例类图
3. 示例代码
1 package designpatterns.chain; 2 3 public class PurchaseRequest { 4 private double amount; //采购金额 5 private int number; //采购单编号 6 private String purpose; //采购目的 7 8 public PurchaseRequest(double amount, int number, String purpose) { 9 super(); 10 this.amount = amount; 11 this.number = number; 12 this.purpose = purpose; 13 } 14 15 public double getAmount() { 16 return amount; 17 } 18 19 public void setAmount(double amount) { 20 this.amount = amount; 21 } 22 23 public int getNumber() { 24 return number; 25 } 26 27 public void setNumber(int number) { 28 this.number = number; 29 } 30 31 public String getPurpose() { 32 return purpose; 33 } 34 35 public void setPurpose(String purpose) { 36 this.purpose = purpose; 37 } 38 39 }
1 package designpatterns.chain; 2 3 public abstract class Approver { 4 protected Approver successor; //定义后继对象 5 protected String name; //审批者姓名 6 7 public Approver(String name) { 8 super(); 9 this.name = name; 10 } 11 12 public void setSuccessor(Approver successor) { 13 this.successor = successor; 14 } 15 16 public abstract void processRequest(PurchaseRequest request); 17 18 }
1 package designpatterns.chain; 2 3 public class Director extends Approver { 4 public Director(String name) { 5 super(name); 6 } 7 8 @Override 9 public void processRequest(PurchaseRequest request) { 10 if(request.getAmount() < 50000) { 11 System.out.println("主任" + this.name + "审批采购单:" + 12 request.getNumber() + ",金额:" + request.getAmount() + 13 "元,采购目的:" + request.getPurpose() + "."); 14 }else { 15 this.successor.processRequest(request); 16 } 17 } 18 }
1 package designpatterns.chain; 2 3 public class VicePresident extends Approver { 4 5 public VicePresident(String name) { 6 super(name); 7 } 8 9 @Override 10 public void processRequest(PurchaseRequest request) { 11 if(request.getAmount() < 100000) { 12 System.out.println("副董事长" + this.name + "审批采购单:" + 13 request.getNumber() + ",金额:" + request.getAmount() + 14 "元,采购目的:" + request.getPurpose() + "."); 15 }else { 16 this.successor.processRequest(request); 17 } 18 } 19 20 }
1 package designpatterns.chain; 2 3 public class President extends Approver{ 4 public President(String name) { 5 super(name); 6 } 7 8 @Override 9 public void processRequest(PurchaseRequest request) { 10 if(request.getAmount() < 500000) { 11 System.out.println("董事长" + this.name + "审批采购单:" + 12 request.getNumber() + ",金额:" + request.getAmount() + 13 "元,采购目的:" + request.getPurpose() + "."); 14 }else { 15 this.successor.processRequest(request); 16 } 17 18 } 19 20 }
1 package designpatterns.chain; 2 3 public class Congress extends Approver{ 4 public Congress(String name) { 5 super(name); 6 } 7 8 @Override 9 public void processRequest(PurchaseRequest request) { 10 11 System.out.println("召开董事会审批采购单:" + request.getNumber() + ",金额:" + 12 request.getAmount() + "元,采购目的:" + request.getPurpose() + "."); 13 } 14 15 }
1 package designpatterns.chain; 2 3 public class Client { 4 public static void main(String[] args) { 5 Approver yunyun,meidusha,xuner,meeting; 6 yunyun = new Director("云韵"); 7 meidusha = new VicePresident("美杜莎"); 8 xuner = new President("熏儿"); 9 meeting = new Congress("董事会"); 10 11 //创建职责链 12 yunyun.setSuccessor(meidusha); 13 meidusha.setSuccessor(xuner); 14 xuner.setSuccessor(meeting); 15 16 PurchaseRequest pr1 = new PurchaseRequest(45000, 10001, "购买青莲地心火"); 17 yunyun.processRequest(pr1); 18 19 PurchaseRequest pr2 = new PurchaseRequest(60000, 10002, "陨落心炎"); 20 yunyun.processRequest(pr2); 21 22 PurchaseRequest pr3 = new PurchaseRequest(160000, 10003, "三千焱炎火"); 23 yunyun.processRequest(pr3); 24 25 PurchaseRequest pr4 = new PurchaseRequest(800000, 10004, "购买虚无吞炎"); 26 yunyun.processRequest(pr4); 27 } 28 }
4. 运行结果
职责链模式优/缺点与使用环境
- 职责链模式优点
(1) 链中的对象不需要知道链的结构,由客户端负责链的创建,降低了系统的耦合度
(2) 请求处理对象只需维持一个指向其后继者的引用
(3) 符合开闭原则
- 职责链模式缺点
(1) 由于一个请求没有明确的接收者,那么不能保证它一定会被处理;一个请求也可能因为职责链没有正确配置而得到处理
(2) 如果链的创建不恰当,可能会导致循环调用,让系统陷入死循环
- 职责链模式使用环境
(1) 有多个对象可以处理同一个请求,客户端只需将请求提交到链上,而无需关心请求的处理对象是谁以及它是如何处理的
(2) 在不明确指定接收者的情况下向多个对象中的一个提交一个请求
(3) 可动态指定一组对象处理请求