设计模式(四)——责任链模式

1. 责任链模式的定义

责任链模式(Chain of Responsibility,简称 CoR,也叫职责链模式)是一种行为型设计模式,允许一个请求在一系列处理器(handlers)中传递。每个处理器可以选择自己处理该请求,或者将其传递给下一个处理器。
一个大家比较熟悉的场景是找售后客服,通常是机器人客服先出来接待,然后在你的多次要求下转给人工客服,如果是设备维修可能还需要转到专业人员。这个场景就很适合应用责任链模式。总结一下就是这个模式适用于设计灵活、解耦的请求处理流水线。
在这里插入图片描述

2. 案例分析

2.1 需求

假设你被安排开发一个在线订购系统。在用户下单前,系统需要执行以下检查:

  • 验证用户身份(Authenticate)
  • 若有需要,校验管理员权限(Authorize)
  • 清理和预处理输入数据(Sanitize)
  • 阻止重复失败的请求(安全性)
  • 如果有缓存则直接返回缓存结果

2.2 潜在问题

如果把所有这些检查逻辑写在一个很长的方法里,你会发现:

  • 代码变得冗长混乱,难维护;
  • 添加或移除检查逻辑很麻烦;
  • 想在别处复用检查逻辑会产生大量重复代码。

2.3 基于责任链的解决方案

责任链模式将每个检查逻辑封装为独立的处理器类(handler),在其中定义 handle() 方法来解决上述问题。
每个处理器可以自行决定:

  • 是否处理当前请求;
  • 是否将请求传递给下一个处理器。
    最后将这些处理器串联起来,形成一个处理流水线(chain)
2.3.1 类定义
  • Handler(处理器接口)
  • BaseHandler(可选的抽象基类,提供链式调用逻辑)
  • AuthHandler(认证处理器)
  • SanitizeHandler(数据清理处理器)
  • CacheHandler(缓存处理器)
    每个处理器只需要知道下一个处理器,从而让请求顺序向下传递。
2.3.2 具体实现

步骤 1:定义处理器接口

interface Handler {void handle(Request request);
}

步骤 2:创建基础处理器 BaseHandler(可选)

// BaseHandler 提供了公共逻辑,用于链接和转发请求。
// 它实现了 Handler 接口。
abstract class BaseHandler implements Handler {// 保存下一个处理器的引用private Handler next;/*** 设置链中的下一个处理器。* 允许像这样链式调用:auth.setNext(validation).setNext(logger);** @param next 下一个处理器* @return 返回传入的处理器,用于链式调用*/public BaseHandler setNext(Handler next) {this.next = next;return (BaseHandler) next;}/*** 如果存在下一个处理器,则将请求转发给它。** @param request 需要传递的请求对象*/protected void forward(Request request) {if (next != null) {// 委托给下一个处理器next.handle(request);  }}
}

BaseHandler 是一个抽象类,不能直接使用,而是由具体的处理器(如 AuthHandlerValidationHandler 等)继承。
它封装了职责链的核心逻辑:

  • setNext() 设置下一个处理器并返回它,以便链式调用;
  • forward() 将请求传递给下一个处理器。

具体处理器类只需要关注自身的 handle() 逻辑,执行完后调用 forward(request) 即可。

步骤 3:定义请求对象

class Request {public String user;public boolean isAdmin;public boolean isValid = true;public boolean isCached;// ... 字段可以根据需要扩展
}

步骤 4:创建具体的处理器

// Handler 1: 检查用户是否已登录
class AuthHandler extends BaseHandler {@Overridepublic void handle(Request request) {if (request.user == null) {System.out.println("[Auth] 用户未认证,请求终止。");// 不再向下传递return; }System.out.println("[Auth] 用户已认证。");// 交给下一个处理器forward(request); }
}// Handler 2: 管理员权限校验
class AdminHandler extends BaseHandler {@Overridepublic void handle(Request request) {if (!request.isAdmin) {System.out.println("[Admin] 普通用户,跳过管理员校验。");} else {System.out.println("[Admin] 管理员验证通过。");// 可执行管理员相关逻辑}forward(request);}
}// Handler 3: 数据清理
class SanitizeHandler extends BaseHandler {@Overridepublic void handle(Request request) {System.out.println("[Sanitize] 正在清理数据...");forward(request);}
}

步骤 5:组装责任链

public class ChainApp {public static void main(String[] args) {Request request = new Request();request.user = "哈基米";request.isAdmin = true;Handler chain = new AuthHandler();chain.setNext(new AdminHandler()).setNext(new SanitizeHandler());chain.handle(request);}
}
2.3.3 执行流程
  1. AuthHandler 验证用户;
  2. 验证通过后,将请求传递给 AdminHandler
  3. 再传递到 SanitizeHandler
  4. 如果某个处理器中断了链条,后续处理器将不会执行。

3. 优缺点分析

3.1 优势

  • 处理器可复用,且易于单元测试;
  • 可以在运行时动态配置责任链;
  • 逻辑清晰,符合 单一职责原则(SRP)
  • 处理顺序不在处理器内部硬编码,而是通过链式结构灵活定义。

3.2 缺点

  • 如果链条覆盖不全,可能存在请求未被处理的情况;
  • 请求在长链路中传递时,跟踪路径可能较困难;
  • 动态链条的调试可能比较复杂,需要设计合适的日志记录方式。

4. 使用

4.1 常见应用场景

  • 中间件管道(认证、校验、日志记录)
  • GUI 事件处理(鼠标/键盘事件)
  • 垃圾邮件过滤
  • 文件格式识别

4.2 适用场景

当满足以下条件时,可以考虑使用职责链模式:

  • 有多个对象可以处理同一个请求;
  • 需要解耦请求发送方和接收方;
  • 需要复用或动态调整处理逻辑顺序;
  • 需要在某些条件下提前终止处理流程。

总结

**职责链模式的核心在于灵活性。**使得逻辑可以像流水线一样串联起来,每个处理器专注于一个小任务。合理的使用这种模式可以让代码逻辑更加清晰、便于测试和扩展,还能避免冗长的条件分支。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/919400.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/919400.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MyBatis-Plus基础篇详解

文章目录前言一、简单介绍MyBatis-Plus1.1 特性1.2 架构二、SpringBoot集成MyBatis-Plus2.1 项目搭建2.2 导入所需依赖2.3 配置application.yml2.4 创建实体类2.5 创建Mapper接口2.6 启动类配置三、DQL操作3.1 基础查询3.2 QueryWrapper查询3.3 LambdaQueryWrapper查询3.4 分页…

基于W55MH32Q-EVB 实现 HTTP 服务器配置 OLED 滚动显示信息

目录 1 前言 2 项目环境 2.1 硬件准备 2.2 软件环境 3.硬件连接和方案 3.1 硬件连接 3.2 方案图示 4.例程修改 1 前言 HTTP(超文本传输协议,HyperText Transfer Protocol)是一种用于分布式、协作式、超媒体信息系统的应用层协议, …

YggJS RLogin暗黑霓虹主题登录注册页面 版本:v0.1.1

项目介绍 yggjs_rlogin 是一个专注于 React 登录/注册页面的组件库。本文档介绍“暗黑霓虹”主题:#111 暗色背景 青蓝霓虹描边输入框 赛博朋克光效按钮。 安装说明 安装:pnpm add yggjs_rlogin react react-dom使用:从 yggjs_rlogin 引入组…

大数据毕业设计选题推荐:护肤品店铺运营数据可视化分析系统详解

🍊作者:计算机毕设匠心工作室 🍊简介:毕业后就一直专业从事计算机软件程序开发,至今也有8年工作经验。擅长Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等。 擅长:按照需求定制化开发项目…

【github-action 如何为github action设置secrets/environment】

Using secrets in GitHub Actions 在 GitHub Actions 中使用密钥 Learn how to create secrets at the repository, environment, and organization levels for GitHub Actions workflows. 学习如何在仓库、环境和组织级别为 GitHub Actions 工作流创建密钥。 Creating secre…

宝塔面板Docker安装n8n汉化中文

一、Docker安装N8N 安装配置默认即可,如果端口已被使用,可以自行更改 当状态为运行中时,就可以点击端口:访问N8N 填写完信息后,点击下一步(邮箱要能接收邮件:接收密钥) 点开始 点击发…

F003疫情传染病数据可视化vue+flask+mysql

编号:F003 文章结尾有CSDN官方提供的学长的联系方式!! 欢迎关注B站 ✅ vue flask 前后端分离架构 ✅ 实现中国地图、柱状图、折线图、水地图、环图等多种图形的echarts可视化分析 视频 vueflask爬虫 新冠疫情大屏实现 python 可视化分析项目源码1 系统…

plantsimulation知识点25.8.19 工件不在RGV中心怎么办?

如果出现这种情况,工件不在RGV的中心该怎么处理。首先说一下出现这种情况的原因。因为模拟的是两台RGV共同托举一个工件移动,实际上RGV控制的代码还是写在一条轨道的传感器控制代码中。另一台RGV只是从动的,工件也是在其中任意一台RGV上&…

redis-sentinel基础概念及部署

一. 引言:Redis Sentinel 是 redis 官方提供的高可用解决方案,主要用于监控 Redis 主从集群,在主节点故障时自动完成故障转移,确保服务持续可用。二. 核心功能1. 监控(monitoring):持续检查主节…

LangChain RAG 简述

在 LangChain 中实现 RAG(检索增强生成,Retrieval-Augmented Generation)的核心思路是:让大模型在生成回答前,先从外部知识库(如文档、数据库等)中检索相关信息,再基于检索到的内容生…

GEO 优化专家孟庆涛:技术破壁者重构 AI 时代搜索逻辑

在生成式 AI 重塑全球搜索生态的浪潮中,中国 GEO(生成式引擎优化)领域的开拓者孟庆涛以 "智能决策革命" 的技术框架,颠覆了传统 "发发文章" 的简单认知。作为辽宁粤穗网络科技有限公司总经理兼 GEO 实验室主任…

用relation-graph构建关系图谱 vue版

用relation-graph构建关系图谱 vue版vue文件和Json数据vue文件和Json数据 <template><div><div style"margin-top:0px;width: calc(100% - 10px);height:calc(100vh);"><RelationGraph ref"graphRef" :options"graphOptions&qu…

Python基础-控制结构

控制结构是编程语言中用来控制程序执行流程的语句。Python提供了条件语句、循环语句等控制结构&#xff0c;让程序能够根据不同条件执行不同的代码块。 程序执行流程图&#xff1a; ┌───────────────────────────────────────────…

Java算法之排序

下面我们将讲述七大基于比较的排序算法的基本原理及实现。并从稳定性、时间复杂度、空间复杂度3种性能对每种排序进行分析。 重点&#xff1a;快速排序和堆排序&#xff1b;难点&#xff1a;快速排序和归并排序 目录 一、排序概念 二、常见排序算法的实现 2.1 插入排序 2.…

RabbitMQ:SpringAMQP 多消费者绑定同一队列

目录一、案例需求二、代码实现三、总结生产者源码 消费者源码 一、案例需求 模拟WorkQueue&#xff0c;实现一个队列绑定多个消费者。 在RabbitMQ的控制台创建一个队列&#xff0c;命名为work.queue。在生产者服务中定义测试方法&#xff0c;在1s内产生50条消息&#xff0c;…

Java技术总监的成长之路(技术干货分享)

以下是针对 ​Java技术总监​ 在 Linux 环境下搭建企业级开发环境的完整指南&#xff0c;涵盖 JDK 配置、工程工具链、协作平台及性能优化方案&#xff1a; 本文章仅提供学习&#xff0c;切勿将其用于不法手段&#xff01; 一、核心环境搭建 1. ​JDK 安装与调优​ ​版本选择…

C++代码解释:实现一个 mystring 类,用于表示字符串,实现构造函数,默认构造长度为 10 的空间,提供打印字符串,获取空间大小,修改内容的成员函数

题目代码#include <cstring> // 包含字符串处理函数库&#xff0c;如strlen、strncpy等 #include <iostream> // 包含输入输出流库&#xff0c;用于cout等操作 using namespace std; // 使用标准命名空间&#xff0c;避免重复书写std::class mystring { // 定…

如何解决IDEA/Datagrip无法连接数据库的问题:解决方法为添加参数-Djava.net.preferIPv4Stack=true

如何解决IDEA/Datagrip无法连接数据库的问题&#xff1a;解决方法为添加参数-Djava.net.preferIPv4Stacktrue 引言 在开发过程中&#xff0c;我们常常使用集成开发环境&#xff08;IDE&#xff09;如 IntelliJ IDEA 或 JetBrains DataGrip 来与数据库进行交互。然而&#xff…

走进数字时代,融入数字生活,构建数字生态

一、准备在IT行业深耕十七年&#xff0c;始终专注于企业生产经营中的实际应用问题&#xff0c;历经开发、测试、运维、实施、架构设计等多个技术岗位&#xff0c;并参与肉制品的生产与销售业务&#xff0c;推进了企业主业的市场管理落地&#xff0c;积累了业务与信息技术融合的…

【Vue开发】在Vite+Vue3项目中实现离线Iconify图标方案

在ViteVue3项目中实现离线Iconify图标方案 项目背景 当前项目需要部署到无网络连接的离线环境&#xff0c;因此需要将Iconify图标集打包到项目构建结果中&#xff0c;实现完全离线使用。 技术环境 框架: Vue 3构建工具: Vite核心依赖:"iconify/json": "^2.2…