设计模式-责任链

之前写代码的时候看到过有审批场景使用了责任链,当时大概看了一下代码实现,今天终于有时间抽出来梳理一下,下面是本文的大纲:

使用场景
审批场景的普遍应用
实际案例:HttpClient中的责任链模式
责任链模式在事件处理、日志记录和过滤器链中的应用
责任链模式实现方式一代码实现
接口和具体处理器类的设计
处理器类的链式结构
客户端使用责任链的示例
责任链模式实现方式二代码实现(简易版)
Spring框架的 @Order 注解的应用
利用 @Order 注解实现的责任链模式
客户端通过构造函数注入实现责任链
HttpClient中的责任链模式(之前遇到过)

使用场景

查了一下大概的使用场景,其实审批场景使用的会比较多,我记得自己第一次看到责任链的时候是在看HttpClient的代码的时候,用了责任链进行请求体的数据传递,只不过当时自己的工程能力还不是特别的完善,因此简单看了个大概就略过了,今天顺便一起梳理了。

  1. 当程序需要使用不同方式处理不同种类请求, 而且请求类型和顺序预先未知时, 可以使用责任链模式。该模式能将多个处理者连接成一条链。 接收到请求后, 它会 “询问” 每个处理者是否能够对其进行处理。 这样所有处理者都有机会来处理请求。

  2. 当必须按顺序执行多个处理者时, 可以使用该模式。无论你以何种顺序将处理者连接成一条链, 所有请求都会严格按照顺序通过链上的处理者。

  3. 如果所需处理者及其顺序必须在运行时进行改变, 可以使用责任链模式。如果在处理者类中有对引用成员变量的设定方法, 你将能动态地插入和移除处理者, 或者改变其顺序。
    在这里插入图片描述

责任链常见的使用场景包括审批流程、事件处理、日志记录、过滤器链等。例如,在一个审批流程中,不同级别的审批人员可以组成一个责任链,每个审批人员处理自己能够处理的审批请求,如果自己无法处理,则将请求传递给下一个审批人员。这样可以动态地调整审批流程,而不需要修改整个系统的代码。

责任链结构
在这里插入图片描述

代码实现,方式一

先给一个责任链的实现代码,思路其实还好,有点类似链表的实现方式,每一个类尝试去进行处理,如果处理不了就交给下一个类,每一个类会按照顺序保存下一个类的地址,这是不是有点类似于链表的结构?当然其实审批流的场景也类似链表的结构,什么时候路由到下一个节点什么时候结束这些都可以收敛到类里面。

// 定义处理请求的接口
interface Handler {
    void handleRequest(Request request);
}

// 具体处理器类
class ConcreteHandler1 implements Handler {
    private Handler nextHandler;

    public void setNextHandler(Handler nextHandler) {
        this.nextHandler = nextHandler;
    }

    @Override
    public void handleRequest(Request request) {
        // 根据具体业务逻辑判断是否能处理请求
        if (request.getType().equals("Type1")) {
            System.out.println("ConcreteHandler1处理请求:" + request.getContent());
        } else {
            // 如果不能处理,则将请求传递给下一个处理器
            if (nextHandler != null) {
                nextHandler.handleRequest(request);
            } else {
                System.out.println("没有处理器能够处理该请求");
            }
        }
    }
}

class ConcreteHandler2 implements Handler {
    private Handler nextHandler;

    public void setNextHandler(Handler nextHandler) {
        this.nextHandler = nextHandler;
    }

    @Override
    public void handleRequest(Request request) {
        if (request.getType().equals("Type2")) {
            System.out.println("ConcreteHandler2处理请求:" + request.getContent());
        } else {
            if (nextHandler != null) {
                nextHandler.handleRequest(request);
            } else {
                System.out.println("没有处理器能够处理该请求");
            }
        }
    }
}

// 请求类
class Request {
    private String type;
    private String content;

    public Request(String type, String content) {
        this.type = type;
        this.content = content;
    }

    public String getType() {
        return type;
    }

    public String getContent() {
        return content;
    }
}

// 客户端使用责任链
public class ChainOfResponsibilityExample {
    public static void main(String[] args) {
        // 创建具体处理器
        ConcreteHandler1 handler1 = new ConcreteHandler1();
        ConcreteHandler2 handler2 = new ConcreteHandler2();

        // 设置责任链关系
        handler1.setNextHandler(handler2);

        // 创建请求
        Request request1 = new Request("Type1", "请求类型1");
        Request request2 = new Request("Type2", "请求类型2");
        Request request3 = new Request("Type3", "请求类型3");

        // 客户端提交请求
        handler1.handleRequest(request1);
        handler1.handleRequest(request2);
        handler1.handleRequest(request3);
    }
}

代码实现,方式二

另外其实还有一个非常简单的实现思路,我记得之前自己看到的责任链实现是基于@Order注解来实现的,找GPT实现了一版当时的代码case,示例如下,这种实现其实能够解决大部分的问题并且非常的简单

public interface Handler {
    void handleRequest(Request request);
}

@Component
@Order(1)
public class ConcreteHandler1 implements Handler {
    @Override
    public void handleRequest(Request request) {
        System.out.println("ConcreteHandler1处理请求:" + request.getContent());
    }
}

@Component
@Order(2)
public class ConcreteHandler2 implements Handler {
    @Override
    public void handleRequest(Request request) {
        System.out.println("ConcreteHandler2处理请求:" + request.getContent());
    }
}

@Component
public class ChainClient {
    private final List<Handler> handlers;

    @Autowired
    public ChainClient(List<Handler> handlers) {
        this.handlers = handlers;
    }

    public void executeChain(Request request) {
        for (Handler handler : handlers) {
            handler.handleRequest(request);
        }
    }
}

在这个例子中,ConcreteHandler1 和 ConcreteHandler2 使用 @Order 注解标记了它们的执行顺序。客户端类 ChainClient 通过构造函数注入所有的处理器,并按照它们的顺序循环调用 handleRequest 方法,从而触发责任链的执行。

HttpClient的责任链

HttpClient 库在内部使用了责任链模式的一种形式。具体而言,它采用了拦截器(Interceptor)机制,这是责任链的一种实现方式。

拦截器机制在 HttpClient 中的工作方式如下:

请求拦截器: 请求拦截器负责在发送之前修改即将发送的 HTTP 请求。它们可以添加头部信息、修改请求方法,或在请求上执行其他操作。

响应拦截器: 响应拦截器负责在将响应返回给调用者之前处理收到的 HTTP 响应。它们可以从响应中提取信息、处理重定向,或在响应上执行其他操作。

执行拦截器: 执行拦截器负责执行 HTTP 请求并获取响应。它在整个请求生命周期中扮演了至关重要的角色,从请求的创建到响应的处理。

每个拦截器都是责任链的一部分,并且链式执行。

写完之后忽然想起了自己之前稍微整理的一版责任链,当时大概是刚开始学java的时候整理的,自己梳理了一个大概的流程图,提供一下跳转链接

https://blog.csdn.net/xiaocaij_icai/article/details/125578282?spm=1001.2014.3001.5501

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RocketMQ学习总结

一、架构 1、NameServer&#xff1a;注册中心。Broker信息注册到NameServer&#xff1b;producer/consumer根据某个topic通过NameServer获取对应broker的路由信息 &#xff1b; 2、Broker&#xff1a;负责存储、拉取、转发消息&#xff1b; 3、Producer&#xff1a;消息生产者…

creature_summon_groups

字段介绍 这个表保存了关于临时召唤生物的数据 creature_summon_groups summonerId&#xff08;召唤者ID&#xff09; summonerType 0 时&#xff0c;此处为 creature 的 entrysummonerType 1 时&#xff0c;此处为 gameobject 的 entrysummonerType 2 时&#xff0c;此处…

从设备维修到机器视觉:我的职业发展之路

大家好&#xff01;我是学员向工&#xff0c;今天很高兴有机会与大家分享我的职业经历。十年前&#xff0c;18岁中专毕业的那年&#xff0c;我踏入社会&#xff0c;至今已经过去了十年。一开始&#xff0c;我主要从事设备的维修、装配、钳工和电工等多岗位工作。 然而&#xff…

大数据关联规则挖掘:Apriori算法的深度探讨

文章目录 大数据关联规则挖掘&#xff1a;Apriori算法的深度探讨一、简介什么是关联规则挖掘&#xff1f;什么是频繁项集&#xff1f;什么是支持度与置信度&#xff1f;Apriori算法的重要性应用场景 二、理论基础项和项集支持度&#xff08;Support&#xff09;置信度&#xff…

༺༽༾ཊ—Unity之-02-简单工厂模式—ཏ༿༼༻

首先我们打开一个项目 在这个初始界面我们需要做一些准备工作 建基础通用包 创建一个Plane 重置后 缩放100倍 加一个颜色 任务&#xff1a;使用【简单工厂模式】生成四种不同怪物 【按不同路径移动】 首先资源商店下载四个怪物模型 接下来我们选取四个怪物作为预制体并分别起名…

【Java并发】聊聊concurrentHashMap扩容核心流程

扩容 什么时候扩容 链表转红黑树。需要判断数组长度&#xff0c;触发扩容调用putAll() , 触发tryPresize() 方法数据量达到阈值 tryPresize-初始化数组 // 扩容前操作&#xff0c;putAll or 链表转红黑树 // size是原数组长度 * 2private final void tryPresize(int size) {…

如何在Servlet中获取请求参数的值

看看这个大佬做的动图吧&#xff01; 在Servlet中&#xff0c;你可以使用HttpServletRequest对象来获取请求参数的值。HttpServletRequest对象提供了一些方法&#xff0c;允许你访问从客户端发送的请求信息。以下是一些获取请求参数的常用方法&#xff1a; getParameter(String…

《SPSS统计学基础与实证研究应用精解》视频讲解:变量和样本观测值基本操作

《SPSS统计学基础与实证研究应用精解》4.1 视频讲解 视频为《SPSS统计学基础与实证研究应用精解》张甜 杨维忠著 清华大学出版社 一书的随书赠送视频讲解4.1节内容。本书已正式出版上市&#xff0c;当当、京东、淘宝等平台热销中&#xff0c;搜索书名即可。本书旨在手把手教会使…

k8s-ingress一

Comfigmap&#xff1a;存储数据 Date&#xff1a; Key&#xff1a;value 挂载的方式&#xff0c;把配置信息传给容器 生产当中的yml文件很长&#xff1a; 有deployment 容器的探针 资源限制 Configmap 存储卷 Service Ingress K8s的对外服务&#xff0c;ingress Se…

2023年总结我所经历的技术大变革

&#x1f4e2;欢迎点赞 &#xff1a;&#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff0c;赐人玫瑰&#xff0c;手留余香&#xff01;&#x1f4e2;本文作者&#xff1a;由webmote 原创&#x1f4e2;作者格言&#xff1a;新的征程&#xff0c;我们面对的不仅…

只需要1天+10元,上线我的第①个工具站 - 50个工具站打卡计划

2023年用了一整年的时间探索技术变现的方式&#xff0c;学习到了特别多的理论知识。2024年到了爆发的时间了。今年计划上线50款出海工具站计划&#xff0c;我会详细记录开发工具站的全部流程。 工具站的核心任务是找到关键字&#xff0c;找对关键词并成功注册到适当的域名&…

logstack 日志技术栈-04-opensource 开源工具 SigNoz+Graylog

3. SigNoz SigNoz 是一个日志收集和分析工具&#xff0c;可以收集和管理来自各种来源的日志、指标、跟踪和异常。 它为使用 OpenTelemetry 检测应用程序提供本机支持&#xff0c;以防止供应商锁定&#xff0c;将收集到的数据存储在 ClickHouse 中&#xff0c;然后在用户友好的…

༺༽༾ཊ—Unity之-01-单例模式—ཏ༿༼༻

在游戏开发过程中&#xff0c;我们会创建各种各样的类&#xff0c;再用new生成实例&#xff0c;有些时候我们需要这个类在整个游戏中是唯一出现的&#xff0c;比如一些管理器比如声音管理器等&#xff0c;没必要创建很多实例&#xff0c;就算有很多模块需要各种声音功能&#x…

NSIS来打包windows安装程序,开源免费简单小巧,支持中文

NSIS (Nullsoft脚本安装系统)是一个专业的开源系统&#xff0c;用于创建 Windows 安装程序。它被设计成尽可能小和灵活&#xff0c;因此非常适合互联网分发&#xff0c;并且原生支持中文&#xff0c;不像inno setup还需要你单独安装一个中文语言包。 NSIS官网&#xff1a;NSIS…

二叉树进阶oj题目

二叉树进阶oj题目 两个结点的最近公共祖先前序中序&#xff08;中序后序&#xff09;还原二叉树 1、两个结点的最近公共祖先&#xff08;两种方法&#xff09; leetcode链接 题目描述&#xff1a;给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共…

【Linux系统编程】环境变量详解

文章目录 1. 环境变量的基本概念2. 如何理解呢&#xff1f;&#xff08;测试PATH&#xff09;2.1 切入点1查看具体的环境变量原因剖析常见环境变量 2.2 切入点2给PATH环境变量添加新路径将我们自己的命令拷贝到PATH已有路径里面 2.3 切入点3 3. 显示所有环境变量4. 测试HOME5. …

【浅谈Linux中批量化注释和批量化去注释】

这篇博客主要是关于Linux中注释与去注释&#xff0c;在Linux和vs等编译器中代码行的注释和去注释会有很大不同&#xff0c;Linux中主要使用指令的方式来进行。 目录 批量化注释 批量化去注释 批量化注释 操作 ctrlv,hjkl区域选择&#xff08;主要使用j-下移&#xff09;&…

GPT应用_PrivateGPT

项目地址&#xff1a;https://github.com/imartinez/privateGPT 1 功能 1.1 整体功能&#xff0c;想解决什么问题 搭建完整的 RAG 系统&#xff0c;与 FastGPT 相比&#xff0c;界面比较简单。但是底层支持比较丰富&#xff0c;可用于知识库的完全本地部署&#xff0c;包含大…

Ubuntu22.04安装GitLab

如果我们是自己本地进行开发,使用Git的简单版本管理功能即可。但如果要做协同开发,使用GitLab自己部署Git代码仓库,是一个不错的选择。 笔者曾使用过svn和Git,相比较而言,Git的使用体验更好。 那么我们接下来安装一下。 安装 首先是升级下包源信息 sudo apt update …

.NET国产化改造探索(六)、银河麒麟操作系统中安装多个.NET版本

随着时代的发展以及近年来信创工作和…废话就不多说了&#xff0c;这个系列就是为.NET遇到国产化需求的一个闭坑系列。接下来&#xff0c;看操作。 上一篇文章介绍了如何在银河麒麟操作系统上&#xff0c;使用Nginx.NET程序实现自启动。本文介绍下如何在一个环境中&#xff0c;…
最新文章