《解锁高效流程设计:深度剖析责任链模式与实战应用》

news/2024/9/29 0:20:36/

《解锁高效流程设计:深度剖析责任链模式与实战应用》

责任链模式 是一种行为设计模式,它允许多个对象来处理请求,而不预先指定具体的处理者。多个处理对象被连接成一条链,沿着这条链传递请求,直到某个处理对象决定处理这个请求为止。责任链模式通过将请求的发送者与接收者解耦,来提高系统的灵活性。

UML 类图:责任链模式

在这里插入图片描述

角色说明

  1. Handler(抽象处理者):定义处理请求的接口,通常包含一个 setNext() 方法用于设置下一个处理者,以及 handleRequest() 方法处理请求或将其传递给下一个处理者。
  2. ConcreteHandler(具体处理者):具体处理请求的类。如果它能处理请求则直接处理,否则将请求传递给下一个处理者。
  3. 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 {@Overridepublic 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 {@Overridepublic 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 {@Overridepublic 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-elseswitch-case 语句,代码变得更加清晰且易于维护。

责任链模式的应用场景

  1. 审批流程
    • 比如企业的请假审批、费用报销审批流程。不同的审批人员有不同的权限,依次审批请求。
  2. 日志处理
    • 日志系统可以通过责任链模式,将日志消息依次传递给不同的处理者(如文件日志处理器、数据库日志处理器等)。
  3. 事件处理系统
    • GUI 事件处理,比如用户点击按钮时,会沿着事件链将事件分发给不同的事件处理器,直到事件被处理

SpringMVC 源码中的责任链模式剖析

责任链模式 在 SpringMVC 中被广泛使用,特别是在处理 HTTP 请求的过程中。SpringMVC 通过一系列的拦截器链过滤器链处理器适配器链等来解耦请求的处理方式,这些链条中的各个元素会根据自身职责处理请求或将其传递给下一个元素,这种设计非常符合责任链模式的思想。

接下来我们将剖析 SpringMVC 中责任链模式的几个典型应用场景,包括:

  1. DispatcherServlet 的处理链
  2. HandlerInterceptor 拦截器链
  3. HandlerExceptionResolver 处理器链

1. DispatcherServlet 的处理链

背景:

DispatcherServlet 是 SpringMVC 的核心,它作为前端控制器,负责接收 HTTP 请求并将其分发给合适的处理器进行处理。DispatcherServlet 并不是直接处理请求的,它依赖一系列的处理器链,包括处理器映射(HandlerMapping)处理器适配器(HandlerAdapter) 等。这些组件的设计符合责任链模式的思想。

工作流程:
  1. DispatcherServlet 接收请求后,会依次调用配置的多个 HandlerMapping 来找到合适的处理器。
  2. 找到处理器后,依次调用配置的多个 HandlerAdapter 来处理该处理器。
  3. 若请求处理失败,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 负责处理不同类型的请求处理器。

总结

优点:

  1. 降低耦合度:请求的发送者与接收者解耦,发送者不需要知道请求是由哪个具体的处理者处理的。
  2. 动态组合:可以灵活地增加或修改处理者链中的处理者,处理链的结构可以在运行时动态修改。
  3. 符合开闭原则:新的处理者可以很容易地加入到责任链中,不需要修改现有的处理者类。

缺点:

  1. 请求没有保证被处理:如果处理链中的所有处理者都没有处理请求,可能会导致请求未被处理的情况。
  2. 性能问题:如果责任链过长,可能会导致处理请求的效率降低,因为每个请求可能要经过多个处理者。

责任链模式 提供了一种灵活的处理请求的方式,通过将多个处理者连接成一条链,使得请求可以沿着链传递,直到被处理。通过使用责任链模式,我们可以解耦请求的发送者和处理者,并且可以动态增加或修改处理者,增强了系统的扩展性。


http://www.ppmy.cn/news/1531676.html

相关文章

【计算机网络 - 基础问题】每日 3 题(二十四)

✍个人博客:Pandaconda-CSDN博客 📣专栏地址:http://t.csdnimg.cn/fYaBd 📚专栏简介:在这个专栏中,我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话,欢迎点赞👍收藏&…

《迁移学习》—— 将 ResNet18 模型迁移到食物分类项目中

文章目录 一、迁移学习的简单介绍1.迁移学习是什么?2.迁移学习的步骤 二、数据集介绍三、代码实现1. 步骤2.所用到方法介绍的文章链接3. 完整代码 一、迁移学习的简单介绍 1.迁移学习是什么? 迁移学习是指利用已经训练好的模型,在新的任务上…

QtCreator的界面

编辑 advanced Auto-indent Selection:自动缩进选择。将所选内容按照预设的缩进规则进行缩进。Rewrap Paragraph:重新换行段落。将一段文字根据指定宽度重新排版。Visualize Whitespace:可视化空白字符。显示通常不可见的空格、制表符等空白…

element ui 精确控制日期控件 date-picker

https://github.com/element-plus/element-plus/discussions/17378 -- 某组件 xxx.vue ... <el-date-pickerv-model"timeRange"type"daterange"range-separator"-"start-placeholder"开始日期"end-placeholder"结束日期"…

QTday1代码的形式实现登录框

代码注释 main.cpp #include "widget.h"#include <QApplication>int main(int argc, char *argv[]) {QApplication a(argc, argv);//调用应用程序类的有参构造的实例化对象Widget w;//调用自定义的有参构造实例化的对象w.show();//调用该类的父类里的成员函数…

spring6启用Log4j2日志

pom文件 <!--log4j2的依赖--> <dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.23.1</version> </dependency> <dependency><groupId>org.apache…

C++入门编程题(力扣):字符串中最多数目的子序列

1.题目描述&#xff1a; 给你一个下标从0开始的字符串 text 和另一个下标从0开始且长度为 2 的字符串 pattern两者都只包含小写英文字母。 你可以在 text 中任意位置插入 一个 字符&#xff0c;这个插入的字符必须是 pattern[0]或者 pattern[1]。 注意&#xff0c;这个字符可以…

Spring Boot 基础入门指南

1. 什么是 Spring Boot&#xff1f; Spring Boot 是一个用于简化 Spring 应用程序开发的框架&#xff0c;旨在让开发者快速构建独立的、生产级的 Spring 应用。它提供了自动配置、嵌入式服务器和一系列开箱即用的功能&#xff0c;降低了应用程序的开发和部署难度。 2. Spring…