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