一、职责链模式介绍
职责链模式,又叫责任链模式,为请求创建了一个接受者对象的链。这种模式对请求的发送者和接受者进行解耦。职责链模式中,每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依次类推。
职责链模式,使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
二、职责链模式原理
说明:
1)Handler:抽象的处理者。定义了一个处理请求的接口,同时含有另外Handler
2)ConcreteHandlerA/ConcreteHandlerB:具体的处理者。处理它自己负责的请求,可以访问它的后继者(即下一个处理者)。如果可以处理当前请求,则处理,否则就将该请求交个后继者去处理,从而形成一个职责链
3)request:含有多个属性,表示一个请求
三、职责类模式例子
学校有OA系统的采购审批项目,需求是:1)采购员采购教学器材;2)如果金额小于等于5000,由教学主任审批;3)如果金额小于等于10000;由院长审批;4)如果金额小于等于30000,由副院长审批;5)如果金额超过30000以上,由校长审批。请设计程序完成采购审批项目。
第一种解决方案:传统方案
传统方式是接收到一个采购请求后,根据采购金额来调用对应的Approver完成审批。但在传统方式中,客户端会使用到分支判断来对不同的采购请求处理,这样存在如下问题:①如果各个级别的人员审批金额发生变化,在客户端也需要变化;②客户端必须明确地知道有多少个审批级别和访问。这样对一个采购请求进行处理和Approver就存在强耦合关系,不利于代码的维护。我们可以使用职责链模式来解决上述问题。
第二种解决方案:职责链模式
类图如下所示:
代码如下所示:
创建PurchaseRequest类:
//请求类
public class PurchaseRequest{
//请求类型
private int type = 0;
private float price = 0.0f;
private int id = 0;
public PurchaseRequest(int type, float price, int id){
this.type = type;
this.price = price;
this.id = id;
}
public int getType(){
return type;
}
public float getPrice(){
return price;
}
public int getId(){
return id;
}
}
创建Approver抽象类及其子类:
public abstract class Approver{
private String name;
//下一个处理者
Approver approver;
public Approver(String name){
this.name = name;
}
//下一个处理者
public void setApprover(Approver approver){
this.approver = approver;
}
//处理审批请求的方法,得到一个请求,处理是子类完成,因此该方法做成抽象
public abstract void processRequest(PruchaseRequest request);
}
public class DepartmentApprover extends Approver{
public DepartmentApprover(){
super(name);
}
public void processRequest(PurchaseRequest request){
if(request.getPrice() <= 5000){
System.out.println("请求编号id =>" + request.getId() + "被" + this.name + "审批");
} else {
approver.processRequest(request);
}
}
}
public class CollegeApprover extends Approver{
public CollegeApprover(){
super(name);
}
public void processRequest(PurchaseRequest request){
if(request.getPrice() > 5000 && request.getPrice() <= 10000){
System.out.println("请求编号id =>" + request.getId() + "被" + this.name + "审批");
} else {
approver.processRequest(request);
}
}
}
public class ViceSchoolMasterApprover extends Approver{
public ViceSchoolMasterApprover(){
super(name);
}
public void processRequest(PurchaseRequest request){
if(request.getPrice() > 10000 && request.getPrice() <= 30000){
System.out.println("请求编号id =>" + request.getId() + "被" + this.name + "审批");
} else {
approver.processRequest(request);
}
}
}
public class SchoolMasterApprover extends Approver{
public SchoolMasterApprover(){
super(name);
}
public void processRequest(PurchaseRequest request){
if(request.getPrice() > 30000){
System.out.println("请求编号id =>" + request.getId() + "被" + this.name + "审批");
} else {
approver.processRequest(request);
}
}
}
创建Client类:
public class Client{
public static void main(String[] args){
PurchaseRequest request = new PurchaseRequest(1, 31000F, 1);
DepartmentApprover deptApprover = new DepartmentApprover("张主任");
CollegeApprover collegeApprover = new CollegeApprover("李院长");
ViceSchoolMasterApprover vsmApprover = new ViceSchoolMasterApprover("王副校长");
SchoolMasterApprover smApprover = new SchoolMasterApprover("陈校长");
deptApprover.setApprover(collegeApprover);
collegeApprover.setApprover(vsmApprover);
vsmApprover.setApprover(smApprover);
smApprover.setApprover(deptApprover);
deptApprover.processRequest(request);
}
}
四、职责链模式注意事项和细节
1)将请求和处理分开,实现解耦,提高系统的灵活性
2)简化了对象,使对象不需要知道链结构
3)性能会受到影响,特别是在链比较长的时候,因此需控制链中最大节点数量,一般通过在Handler中设置一个最大节点数量,在setNext()方法中判断是否已经超过阈值,超过则不允许该链建立,避免出现超长链而破坏系统性能
4)调试不方便,采用了类似递归的方法,调试时逻辑可能比较复杂
5)最佳应用场景:有多个对象可以处理同一个请求时,比如:多级请求、请假/加薪等审批流程、Java web中Tomcat对Encoding的处理、拦截器