1.概述
责任链模式(Chain of Responsibility Pattern)是为请求创建了一个接收者对象的链,让请求沿着这条链进行传播,直到有对象处理它为止,它属于典型的行为型模式。这种方式降低了发送者和处理者之间的耦合关系,使多个对象都有机会处理请求。
责任链模式的使用场景很多,例如Struts2中的拦截器,SpringMVC中的HandlerExecutionChain等。本文将分析责任链的原理及使用,帮助大家更好地理解。
2.原理及使用
2.1 原理
责任链模式的类图如下:
责任链包含的核心角色如下:
抽象处理者角色(Handler):定义一个处理请求的接口,包含抽象处理方法和设置后继连接者方法;
具体处理者(HandlerA、HandlerB):实现抽象处理者处理方法的具体类,判断能否处理本次请求,如果可以则直接处理,不可以则将请求传给后继者;
处理链创建类(ChainOfHandler):创建处理链,并向链首的处理者提交请求,它不关心处理细节和请求的传递过程。
2.2 案例
有一个高校资源审批流程,加入采购最小单位是学院,当采购金额小于1万时,院长审批即可;当金额大于1万且小于2万时,需要学校财政处处长审批;当金额大于2万且小于3万时,需要副校长进行审批;当金额大于3万时,需要校长审批。
传统处理方式如下:
通过定义一个审批接口Approval,院长、财政处处长、副校长、校长分别实现该接口中的approve()方法,实现审批流程。客户端会关联具体的采购类Purchase,该类包含采购具体用品及总价,在Client类中,调用Purchase类的getTotalPrice()方法获取总价后,需要编写如下代码:
Purchase purchase = new Purchase();
double totalPrice = purchase.getTotalPrice();
Dean dean = new Dean();
FinanceMaster financeMaster = new FinanceMaster();
VicePrincipal vicePrincipal = new VicePrincipal();
SchoolMaster schoolMaster = new SchoolMaster();
if (totalPrice > 0 && totalPrice < 10000) {
dean.approve();
} else if (totalPrice >= 10000 && totalPrice < 20000) {
financeMaster.approve();
} else if (totalPrice >= 20000 && totalPrice < 30000) {
vicePrincipal.approve();
} else if (totalPrice >= 30000) {
schoolMaster.approve();
}
上述代码中需要在if…else…语句中判断,根据采购总价来选择不同的人去审批。这种方式的缺陷在于如果各个级别的人员审批金额发生变化或者审批人员发生变化,客户端必须做出相应的改变,造成了一种强耦合关系,不利于代码维护和扩展。
采用责任链模式进行改造,结果如下:
编码如下:
public interface Approval {
void approve(Double totalPrice);
void setNext(Approval approval);
}
public class Dean implements Approval {
private Double totalPrice;
private Approval approval;
public Dean(Double totalPrice) {
this.totalPrice = totalPrice;
}
@Override
public void approve(Double price) {
if (price > 0 && price < totalPrice) {
System.out.println("院长开始审批---------");
System.out.println("院长审批通过---------");
} else {
if (approval != null) {
approval.approve(price);
} else {
System.out.println("无人能够处理");
}
}
}
@Override
public void setNext(Approval approval) {
this.approval = approval;
}
}
public class FinanceMaster implements Approval {
private Double totalPrice;
private Approval approval;
public FinanceMaster(Double totalPrice) {
this.totalPrice = totalPrice;
}
@Override
public void approve(Double price) {
if (price >= 10000 && price < totalPrice) {
System.out.println("财政处处长开始审批---------");
System.out.println("财政处处长审批通过---------");
} else {
if (approval != null) {
approval.approve(price);
} else {
System.out.println("无人能够处理");
}
}
}
@Override
public void setNext(Approval approval) {
this.approval = approval;
}
}
public class VicePrincipal implements Approval {
private Double totalPrice;
private Approval approval;
public VicePrincipal(Double totalPrice) {
this.totalPrice = totalPrice;
}
@Override
public void approve(Double price) {
if (price >= 20000 && price < totalPrice) {
System.out.println("副校长开始审批---------");
System.out.println("副校长审批通过---------");
} else {
if (approval != null) {
approval.approve(price);
} else {
System.out.println("无人能够处理");
}
}
}
@Override
public void setNext(Approval approval) {
this.approval = approval;
}
}
public class SchoolMaster implements Approval {
private Double totalPrice;
private Approval approval;
public SchoolMaster(Double totalPrice) {
this.totalPrice = totalPrice;
}
@Override
public void approve(Double price) {
if (price >= 30000) {
System.out.println("校长开始审批---------");
System.out.println("校长审批通过---------");
} else {
if (approval != null) {
approval.approve(price);
} else {
System.out.println("无人能够处理");
}
}
}
@Override
public void setNext(Approval approval) {
this.approval = approval;
}
}
import lombok.Data;
@Data
public class Purchase {
/**
* 采购类型
*/
private Integer type;
/**
* 采购数量
*/
private Integer number;
/**
* 采购物品名称
*/
private String name;
/**
* 采购物品总价
*/
private Double totalPrice;
}
public class ChainOfHandler {
private static Purchase purchase = new Purchase();
/**
* 校长审批的类型为4,也就是总价小于10000
*/
private static Dean dean = new Dean(10000.0);
/**
* 校长审批的类型为3,也就是总价大于等于10000,小于20000
*/
private static FinanceMaster financeMaster = new FinanceMaster(20000.0);
/**
* 校长审批的类型为2,也就是总价大于等于20000,小于30000
*/
private static VicePrincipal vicePrincipal = new VicePrincipal(30000.0);
/**
* 校长审批的类型为1,也就是总价大于30000
*/
private static SchoolMaster schoolMaster = new SchoolMaster(30000.0);
public static void setChain() {
dean.setNext(financeMaster);
financeMaster.setNext(vicePrincipal);
vicePrincipal.setNext(schoolMaster);
}
public static void main(String[] args) {
purchase.setName("桌子采购");
purchase.setNumber(500);
purchase.setTotalPrice(50000.0);
purchase.setType(1);
setChain();
dean.approve(purchase.getTotalPrice());
}
}
运行结果如下:
如果设置总金额为50000,得到如下结果:
2.3 责任链的优势与缺点
2.3.1 优势
1、降低了耦合度,它将请求的发送者和接收者解耦;
2、简化了对象,使得调用者不需要知道链的内部结构;
3、符合开闭原则,当给对象增加新的职责时,只需在新增一个具体子链类,调整一下内部链结构即可;
4、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
2.3.2 缺点
1、不能保证请求一定会被链路处理;
2、代码调试时过于复杂,可能会造成循环调用;
3、可能不容易观察运行时的特征,有碍于除错;
4、当链路过长时,会极大影响系统的性能。
2.3.3 注意事项
1、当使用责任链时,需要控制链的长度,避免出现超长链的情况;
2、需要考虑不被链路处理的请求返回情况。
3.小结
1.责任链将请求与处理分开,实现解耦,提高系统的灵活性;
2.简化了对象,使对象不需要知道链路结构;
3.责任链在使用时,需要考虑链路长度情况,避免链路过长,它的主要使用场景是多个对象处理同一个请求,内部有大量逻辑判断。
4.参考文献
1.《设计模式之禅》-秦小波著
2.《大话设计模式》-程杰著
3.https://www.bilibili.com/video/BV1G4411c7N4-尚硅谷设计模式