责任链模式
什么是责任链模式
责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,允许你将请求沿着处理者链进行传递。每个处理者均对请求进行某些处理,并可决定是否将请求沿着链传递下去。这种模式给予请求的处理者更加灵活的组织结构。
在Java中实现责任链模式,通常需要定义一个处理者接口,该接口包含一个或多个方法用于处理请求和决定是否传递请求。
然后,创建具体的处理者类,实现这个接口。 每个处理者可以持有对下一个处理者的引用,从而形成处理者链。
-
优点
- 降低了耦合度: 责任链模式通过将请求的处理逻辑分散到多个处理对象中,减少了请求发送者与多个请求处理者之间的耦合。请求发送者只需要将请求发送到链的头部,而不需要知道链的具体结构或处理逻辑。
- 增强了系统的可扩展性: 当需要增加新的处理逻辑时,只需要创建一个新的处理对象并将其添加到链中即可,无需修改现有代码。这使得系统的扩展变得更加容易和灵活。
- 提高了系统的灵活性: 每个处理对象都可以独立地决定是否处理请求,以及是否将请求传递给下一个处理对象。这种灵活性使得系统可以根据不同的场景和需求进行动态调整。
- 实现了请求的有序处理: 通过合理地安排处理对象在链中的顺序,可以确保请求按照特定的顺序进行处理。这对于某些需要按照特定顺序执行的操作非常有用。
-
缺点
- 可能导致性能问题: 由于请求需要在多个处理对象之间进行传递,因此可能会增加系统的处理时间。特别是在处理链较长或处理逻辑较复杂的情况下,性能问题可能会更加明显。
- 调试难度较大: 当责任链较长且处理逻辑复杂时,调试可能会变得相对困难。因为请求在多个处理对象之间传递,定位问题的来源可能需要跨越多个类和方法。
- 可能导致请求丢失: 如果没有正确设置处理对象的下一个引用,或者处理对象在处理请求时出现了异常,可能会导致请求在链中丢失,从而无法得到处理。
- 可能增加代码的复杂性: 为了实现责任链模式,需要编写多个处理对象的代码,并确保它们之间的正确连接和传递。这可能会增加代码的复杂性,特别是在处理逻辑较为复杂的情况下。
开发中常见场景
- java中,异常机制就是一种责任链模式
- Servlet开发中,过滤器的链式处理
- Struts2中,拦截器的调用也是典型的责任链模式
案例
公司里,请假条的审批流程:
- 请假天数小于3天,主任审批
- 请假天数大于3天,小于10天,经理审批
- 请假天数大于10天,小于30天,总经理审批
- 请假天数大于30天,提示拒绝
UML
- 定义请假单,包含请假人,请假天数,请假原因属性
- 定义一个处理者接口,并提供两个接口:
- 自己的处理方式
- 设置下一处理者
- 定义主任、经理,总经理三个处理者,定义一个属性存储下一处理者引用,自己处理方式接口中,根据需求进行判断处理,否则调用下一处理者进行处理
实现代码
LeaveOrder.java
// 请假单
public class LeaveOrder {// 请假人private String name;// 请假天数private int days;// 原因private String reason;public LeaveOrder(String name, int days, String reason) {this.name = name;this.days = days;this.reason = reason;}public String getName() {return name;}public int getDays() {return days;}public String getReason() {return reason;}
}
LeaveHandle.java
// 定义处理者接口
public interface LeaveHandle {// 定义本人处理方式接口void handleRequest(LeaveOrder leaveOrder);// 定义下一处理者的引用void setNextHandle(LeaveHandle leaveHandle);
}
DirectorLeaveHandle.java
// 主任
public class DirectorLeaveHandle implements LeaveHandle{// 定义一个属性 用于持有下一处理者private LeaveHandle nextHandler;@Overridepublic void handleRequest(LeaveOrder leaveOrder) {if(leaveOrder != null && leaveOrder.getDays() <= 3 && leaveOrder.getDays() > 0){System.out.printf("主任审批-允许请假-请假人:%s-请假天数:%s-理由:%s%n",leaveOrder.getName(),leaveOrder.getDays(),leaveOrder.getReason());}else {// 通过持有引用 调用下已处理者进行处理nextHandler.handleRequest(leaveOrder);}}@Overridepublic void setNextHandle(LeaveHandle leaveHandle) {this.nextHandler = leaveHandle;}
}
ManagerLeaveHandle.java
// 经理
public class ManagerLeaveHandle implements LeaveHandle{// 定义一个属性 用于持有下一处理者private LeaveHandle nextHandler;@Overridepublic void handleRequest(LeaveOrder leaveOrder) {if(leaveOrder != null && leaveOrder.getDays() <= 10 && leaveOrder.getDays() > 3){System.out.printf("经理审批-允许请假-请假人:%s-请假天数:%s-理由:%s%n",leaveOrder.getName(),leaveOrder.getDays(),leaveOrder.getReason());}else {// 通过持有引用 调用下已处理者进行处理nextHandler.handleRequest(leaveOrder);}}@Overridepublic void setNextHandle(LeaveHandle leaveHandle) {this.nextHandler = leaveHandle;}
}
GeneralManagerLeaveHandle.java
// 总经理
public class GeneralManagerLeaveHandle implements LeaveHandle{// 定义一个属性 用于持有下一处理者private LeaveHandle nextHandler;@Overridepublic void handleRequest(LeaveOrder leaveOrder) {if(leaveOrder != null && leaveOrder.getDays() <= 30 && leaveOrder.getDays() > 10){System.out.printf("总经理审批-允许请假-请假人:%s-请假天数:%s-理由:%s%n",leaveOrder.getName(),leaveOrder.getDays(),leaveOrder.getReason());}else {System.out.println("超过30天拒绝请假");}}@Overridepublic void setNextHandle(LeaveHandle leaveHandle) {this.nextHandler = leaveHandle;}
}
TestClient.java
public class TestClient {public static void main(String[] args) {// 创建请假单LeaveOrder order = new LeaveOrder("张三",15,"回家"); 创建处理人// 主任DirectorLeaveHandle directorLeaveHandle = new DirectorLeaveHandle();// 经理ManagerLeaveHandle managerLeaveHandle = new ManagerLeaveHandle();// 总经理GeneralManagerLeaveHandle generalManagerLeaveHandle = new GeneralManagerLeaveHandle();// 设置责任链directorLeaveHandle.setNextHandle(managerLeaveHandle);directorLeaveHandle.setNextHandle(generalManagerLeaveHandle);// 提交请假申请directorLeaveHandle.handleRequest(order);}
}
执行结果:
gitee源码
git clone https://gitee.com/dchh/JavaStudyWorkSpaces.git