《解锁高效流程设计:深度剖析责任链模式与实战应用》
责任链模式 是一种行为设计模式,它允许多个对象来处理请求,而不预先指定具体的处理者。多个处理对象被连接成一条链,沿着这条链传递请求,直到某个处理对象决定处理这个请求为止。责任链模式通过将请求的发送者与接收者解耦,来提高系统的灵活性。
UML 类图:责任链模式
角色说明:
- Handler(抽象处理者) :定义处理请求的接口,通常包含一个
setNext()
方法用于设置下一个处理者,以及handleRequest()
方法处理请求或将其传递给下一个处理者。 - ConcreteHandler(具体处理者):具体处理请求的类。如果它能处理请求则直接处理,否则将请求传递给下一个处理者。
- Request(请求对象):请求对象,包含一些必要的信息,具体的处理者会根据请求中的信息决定是否处理。
实战场景:重构权限审批流程
问题描述:
在企业内部的权限审批系统中,不同的人员可以审批不同级别的权限请求。例如:
- 普通员工只能审批简单权限(如普通数据访问权限)。
- 部门主管可以审批更高级别的权限请求(如敏感数据访问权限)。
- 管理层可以审批最高级别的权限请求(如系统管理权限)。
当一个权限请求发出后,它会沿着审批链传递,直到找到能处理该请求的人员。使用责任链模式,可以让请求沿着处理链传递,并且避免将处理逻辑硬编码在某个具体对象中。
代码实现:权限审批流程的责任链构建
Step 1: 定义请求类
首先,我们定义一个 Request
类来封装权限请求。
java
// 请求类:封装权限请求
public class Request {
private String requestType;
private int permissionLevel;
public Request(String requestType, int permissionLevel) {
this.requestType = requestType;
this.permissionLevel = permissionLevel;
}
public String getRequestType() {
return requestType;
}
public int getPermissionLevel() {
return permissionLevel;
}
}
Step 2: 定义抽象处理者
定义抽象的 Handler
接口,所有具体的处理者都实现该接口。该接口定义了 setNext()
方法用于设置下一个处理者,handleRequest()
方法用于处理请求或将请求传递给下一个处理者。
java
// 抽象处理者接口
public abstract class Handler {
protected Handler nextHandler;
// 设置下一个处理者
public void setNext(Handler nextHandler) {
this.nextHandler = nextHandler;
}
// 抽象方法:处理请求
public abstract void handleRequest(Request request);
}
Step 3: 实现具体的处理者
根据实际的权限审批流程,我们创建三个具体的处理者:普通员工、部门主管、管理层。
普通员工处理者
普通员工只能处理权限级别为 1 的请求。
java
// 具体处理者:普通员工
public class EmployeeHandler extends Handler {
@Override
public void handleRequest(Request request) {
if (request.getPermissionLevel() == 1) {
System.out.println("Employee approves request for: " + request.getRequestType());
} else {
if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
}
}
部门主管处理者
部门主管可以处理权限级别为 2 的请求。
java
// 具体处理者:部门主管
public class SupervisorHandler extends Handler {
@Override
public void handleRequest(Request request) {
if (request.getPermissionLevel() == 2) {
System.out.println("Supervisor approves request for: " + request.getRequestType());
} else {
if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
}
}
管理层处理者
管理层可以处理权限级别为 3 的请求。
java
// 具体处理者:管理层
public class ManagerHandler extends Handler {
@Override
public void handleRequest(Request request) {
if (request.getPermissionLevel() == 3) {
System.out.println("Manager approves request for: " + request.getRequestType());
} else {
System.out.println("Request not approved. No handler for permission level: " + request.getPermissionLevel());
}
}
}
Step 4: 创建处理链并测试
我们可以创建处理链,并将权限请求传递给链中的第一个处理者。
java
public class ChainOfResponsibilityDemo {
public static void main(String[] args) {
// 创建处理者
Handler employee = new EmployeeHandler();
Handler supervisor = new SupervisorHandler();
Handler manager = new ManagerHandler();
// 设置责任链
employee.setNext(supervisor);
supervisor.setNext(manager);
// 创建权限请求
Request request1 = new Request("Access to ordinary data", 1);
Request request2 = new Request("Access to sensitive data", 2);
Request request3 = new Request("System admin access", 3);
Request request4 = new Request("Access to confidential data", 4); // 没有处理者能处理
// 开始处理请求
employee.handleRequest(request1); // 应由普通员工处理
employee.handleRequest(request2); // 应由部门主管处理
employee.handleRequest(request3); // 应由管理层处理
employee.handleRequest(request4); // 没有处理者能处理
}
}
输出结果:
java
Employee approves request for: Access to ordinary data
Supervisor approves request for: Access to sensitive data
Manager approves request for: System admin access
Request not approved. No handler for permission level: 4
责任链模式解决的问题
1.解耦请求发送者和接收者:
- 请求的发送者不知道请求的最终处理者是谁,处理者可以动态地决定是否处理请求或将请求传递给下一个处理者。
2.灵活的责任分配:
- 通过责任链的方式,可以动态地增加或减少处理者。系统可以根据实际需要自由调整处理链,增强了系统的灵活性。
3.避免代码的条件分支嵌套:
- 通过将责任分布在不同的处理者中,避免了大量的
if-else
或switch-case
语句,代码变得更加清晰且易于维护。
责任链模式的应用场景
- 审批流程 :
- 比如企业的请假审批、费用报销审批流程。不同的审批人员有不同的权限,依次审批请求。
- 日志处理 :
- 日志系统可以通过责任链模式,将日志消息依次传递给不同的处理者(如文件日志处理器、数据库日志处理器等)。
- 事件处理系统 :
- GUI 事件处理,比如用户点击按钮时,会沿着事件链将事件分发给不同的事件处理器,直到事件被处理
SpringMVC 源码中的责任链模式剖析
责任链模式 在 SpringMVC 中被广泛使用,特别是在处理 HTTP 请求的过程中。SpringMVC 通过一系列的拦截器链 、过滤器链 、处理器适配器链 等来解耦请求的处理方式,这些链条中的各个元素会根据自身职责处理请求或将其传递给下一个元素,这种设计非常符合责任链模式的思想。
接下来我们将剖析 SpringMVC 中责任链模式的几个典型应用场景,包括:
DispatcherServlet
的处理链HandlerInterceptor
拦截器链HandlerExceptionResolver
处理器链
1. DispatcherServlet
的处理链
背景:
DispatcherServlet
是 SpringMVC 的核心,它作为前端控制器,负责接收 HTTP 请求并将其分发给合适的处理器进行处理。DispatcherServlet
并不是直接处理请求的,它依赖一系列的处理器链,包括处理器映射(HandlerMapping) 、处理器适配器(HandlerAdapter) 等。这些组件的设计符合责任链模式的思想。
工作流程:
DispatcherServlet
接收请求后,会依次调用配置的多个HandlerMapping
来找到合适的处理器。- 找到处理器后,依次调用配置的多个
HandlerAdapter
来处理该处理器。 - 若请求处理失败,
DispatcherServlet
会依次调用配置的HandlerExceptionResolver
来处理异常。
通过这种链式调用,SpringMVC 将处理器映射、处理器适配和异常处理等职责分散到多个组件中,使得请求的处理过程高度灵活。
关键代码剖析:
- 处理器映射链 :
DispatcherServlet
中调用getHandler()
方法时,会遍历所有配置的HandlerMapping
,并找到合适的处理器。
java
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
剖析:
handlerMappings
是一个HandlerMapping
列表,SpringMVC 允许配置多个HandlerMapping
,每个HandlerMapping
都可以处理不同的请求映射。getHandler()
会遍历所有HandlerMapping
,如果一个HandlerMapping
可以处理当前请求,它就会返回对应的处理器,否则请求会被传递给下一个HandlerMapping
。
这里的处理器映射链就是一个典型的责任链模式,每个 HandlerMapping
相当于一个链条上的处理者。
处理器适配器链 : 找到处理器后,DispatcherServlet
会使用 HandlerAdapter
来执行该处理器的业务逻辑。SpringMVC 支持多种类型的处理器(如控制器、异步处理等),因此需要通过不同的 HandlerAdapter
来处理不同类型的处理器。
java
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler + "]");
}
剖析:
handlerAdapters
是一个HandlerAdapter
列表,每个HandlerAdapter
都可以处理不同类型的处理器。getHandlerAdapter()
会依次遍历HandlerAdapter
列表,找到可以处理当前处理器的适配器,并使用它来执行处理器。- 这种处理器适配器的机制也是典型的责任链模式应用,不同的
HandlerAdapter
负责处理不同类型的请求处理器。
总结
优点:
- 降低耦合度:请求的发送者与接收者解耦,发送者不需要知道请求是由哪个具体的处理者处理的。
- 动态组合:可以灵活地增加或修改处理者链中的处理者,处理链的结构可以在运行时动态修改。
- 符合开闭原则:新的处理者可以很容易地加入到责任链中,不需要修改现有的处理者类。
缺点:
- 请求没有保证被处理:如果处理链中的所有处理者都没有处理请求,可能会导致请求未被处理的情况。
- 性能问题:如果责任链过长,可能会导致处理请求的效率降低,因为每个请求可能要经过多个处理者。
责任链模式 提供了一种灵活的处理请求的方式,通过将多个处理者连接成一条链,使得请求可以沿着链传递,直到被处理。通过使用责任链模式,我们可以解耦请求的发送者和处理者,并且可以动态增加或修改处理者,增强了系统的扩展性。