设计模式之责任链模式

news2025/1/24 17:36:30

Chain of responsibility

责任链模式的概念、责任链模式的结构、责任链模式的优缺点、责任链模式的使用场景、责任链模式的实现示例、责任链模式的源码分析


1、责任链模式的概念

  责任链模式,即把请求从链中的一个对象传到下一个对象,知道请求被响应为止,通过这种方式来解耦。为了避免请求发送者与多个请求处理者耦合,通过前一个处理者对下一个处理者的引用而形成请求处理链,当请求发生时将沿着链向下传递,知道被处理为止。

2、责任链模式的结构

  • 抽象处理器:定义请求处理行为,并持有维护一个下一个处理器的引用。
  • 具体处理器:继承自抽象处理器,实现其定义的请求处理行为。
  • 客户端:即请求发起者,创建链并发起请求。

chain-of-responsibility

3、责任链模式的优缺点

  • 优点:
    • 降低了对象之间的耦合度。降低了请求发送者和接受者之间的耦合度。
    • 增强了系统的可扩展性。可以根据需求增加新的请求处理类,满足开闭原则。
    • 增强了给对象指派职责的灵活度。当工作流程发生变化时,可动态的改变链内成员或修改它们的次序,也可动态的新增或删除责任。
    • 责任链简化了对象之间的连接。一个对象只需要持有一个后继引用,不需要持有其它处理者的引用。
    • 责任分担。每个类只需要负责自己该处理的工作,不能处理的传递给下一个对象,明确各类的责任范围,符合类的单一职责原则。
  • 缺点:
    • 不能保证每个请求一定会被处理。由于一个请求没有明确的接受者,所以不能保证它一定会被处理,该请求可能一直传至链尾都没被处理。
    • 职责链的合理性需要客户端来保证,增加了客户端的复杂性,也可能由于错误的职责链设置而导致系统出错。

4、责任链模式的使用场景

  • 多个对象可处理同一个请求,但具体有那个对象处理则在运行时动态决定。
  • 在请求处理者不明确的情况下想多个对象提交一个请求。
  • 需要动态处理一组对象处理请求时。

5、责任链模式的实现示例

抽象处理器:

public abstract class Handler {

    protected static final Integer ZERO = 0;

    protected static final Integer ONE = 1;

    protected static final Integer THREE = 3;

    protected static final Integer SEVEN = 7;

    private Integer start;

    private Integer end;

    private Handler next;

    public Handler(Integer start, Integer end) {
        this.start = start;
        this.end = end;
    }

    public void setNext(Handler next) {
        this.next = next;
    }

    /**
     * 提交
     * @param leaveOfRequest
     */
    public final void submit(LeaveOfRequest leaveOfRequest) {
        int days = leaveOfRequest.getDays();
        if (days <= 0) {
            return;
        }

        if (days >= this.start) {
            this.handler(leaveOfRequest);
            if (this.next != null && days > this.end) {
                this.next.submit(leaveOfRequest);
            } else {
                System.out.println("流程结束");
            }
        }
    }

    /**
     * 处理请求
     * @param leaveOfRequest
     */
    protected abstract void handler(LeaveOfRequest leaveOfRequest);
}

员工处理器:

public class EmployeeHandler extends Handler {

    public EmployeeHandler() {
        super(ZERO, ZERO);
    }

    @Override
    protected void handler(LeaveOfRequest leaveOfRequest) {
        System.out.println("请假条:" + leaveOfRequest.getName() + " 请假 " + leaveOfRequest.getDays() + " 天 原因 "
                + leaveOfRequest.getContent());
    }
}

组长处理器:

public class GroupHandler extends Handler {

    public GroupHandler() {
        super(ZERO, ONE);
    }

    @Override
    protected void handler(LeaveOfRequest leaveOfRequest) {
        System.out.println("组长同意");
    }
}

部门经理处理器:

public class ManagerHandler extends Handler {

    public ManagerHandler() {
        super(ONE, THREE);
    }

    @Override
    protected void handler(LeaveOfRequest leaveOfRequest) {
        System.out.println("部门经理同意");
    }
}

总经理处理器:

public class GeneralHandler extends Handler {

    public GeneralHandler() {
        super(THREE, SEVEN);
    }

    @Override
    protected void handler(LeaveOfRequest leaveOfRequest) {
        System.out.println("总经理同意");
    }
}

请假条(不属于责任链模式组件):

public class LeaveOfRequest {

    private String name;

    private Integer days;

    private String content;

    public LeaveOfRequest(String name, Integer days, String content) {
        this.name = name;
        this.days = days;
        this.content = content;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getDays() {
        return days;
    }

    public void setDays(Integer days) {
        this.days = days;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}

测试:

public class ChainOfResponsibilityTest {

    public static void main(String[] args) {
        LeaveOfRequest leaveOfRequest = new LeaveOfRequest("momo", 5, "调休");

        EmployeeHandler employeeHandler = new EmployeeHandler();
        GroupHandler groupHandler = new GroupHandler();
        ManagerHandler managerHandler = new ManagerHandler();
        GeneralHandler generalHandler = new GeneralHandler();
        employeeHandler.setNext(groupHandler);
        groupHandler.setNext(managerHandler);
        managerHandler.setNext(generalHandler);

        employeeHandler.submit(leaveOfRequest);
    }
}

测试结果:

请假条:momo 请假 5 天 原因 调休
组长同意
部门经理同意
总经理同意
流程结束

6、责任链模式源码分析

  java web 中的 FilterChain 就是责任链模式的典型应用,spring security 中的 SecurityFilterChain 也是责任链模式的典型应用,其在 FilterOrderRegistration 类中声明了默认内置 filter 的顺序,并在 HttpSecurity 类中声明了内部类 OrderedFilter 来承载 Filter,并对外提供了可以指定顺序的 addFilter 方法,以这些手段来明确 filter 在 filter chain 中的执行顺序。

  以下为 FilterChain 实现示例:

chain-of-responsibility-filter-chain

模拟 Request 类:

public interface Request {

}

模拟 Response 类:

public interface Response {

}

模拟 Filter 类:

public interface Filter {

    void doFilter(Request request, Response response, FilterChain filterChain);
}

模拟 FilterChain 类:

public class FilterChain {

    private List<Filter> filters;

    private Integer index;

    public FilterChain() {
        this.filters = new ArrayList<>();
        this.index = 0;
    }

    public FilterChain addFilter(Filter filter) {
        this.filters.add(filter);
        return this;
    }

    public void doFilter(Request request, Response response) {
        if (this.index == this.filters.size()) {
            return;
        }
        Filter filter = this.filters.get(index);
        this.index++;
        filter.doFilter(request, response, this);
    }
}

自定义过滤器一:

public class FirstFilter implements Filter {

    @Override
    public void doFilter(Request request, Response response, FilterChain filterChain) {
        System.out.println("过滤器一执行前");
        filterChain.doFilter(request, response);
        System.out.println("过滤器一执行后");
    }
}

自定义过滤器二:

public class SecondFilter implements Filter {

    @Override
    public void doFilter(Request request, Response response, FilterChain filterChain) {
        System.out.println("过滤器二执行前");
        filterChain.doFilter(request, response);
        System.out.println("过滤器二执行后");
    }
}

自定义过滤器三:

public class ThirdFilter implements Filter {

    @Override
    public void doFilter(Request request, Response response, FilterChain filterChain) {
        System.out.println("过滤器三执行前");
        filterChain.doFilter(request, response);
        System.out.println("过滤器三执行后");
    }
}

测试:

public class FilterTest {

    public static void main(String[] args) {
        FilterChain filterChain = new FilterChain();
        filterChain.addFilter(new FirstFilter())
                .addFilter(new SecondFilter())
                .addFilter(new ThirdFilter());
        filterChain.doFilter(null, null);
    }
}

测试结果:

过滤器一执行前
过滤器二执行前
过滤器三执行前
过滤器三执行后
过滤器二执行后
过滤器一执行后

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

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

相关文章

多数据源事务处理-涉及分布式事务

一. 数据源跨库但是不跨 MySql 实例 这个形式就是数据源在同一个 MySQL 下&#xff0c;但是 jdbc-url 上的数据库配置不同&#xff0c;涉及多个数据库时&#xff0c;如果方法中发生异常&#xff0c;只有开启事务的数据源会发生回滚&#xff0c;其他数据源不会回滚。看到这里可…

禅道 删除回收站

回收站的内容只能进入数据库删 如何访问数据库 1、网页登录数据库 禅道数据库管理用的是adminer&#xff0c;但是为了安全&#xff0c;访问adminer的时候需要身份验证&#xff0c;需要运行/opt/zbox/auth/adduser.sh来添加用户(先 cd /opt/zbox/auth/ 然后执行 ./adduser.sh…

线程和进程 / 进程和线程的区别和联系

&#x1f496; 欢迎来阅读子豪的博客&#xff08;JavaEE篇 &#x1f934;&#xff09; &#x1f449; 有什么宝贵的意见或建议可以在留言区留言 &#x1f4bb; 欢迎 素质三连 点赞关注 收藏 &#x1f9d1;‍&#x1f680;码云仓库&#xff1a;补集王子的代码仓库 不要偷走我小…

飞宇医药冲刺创业板:年营收4.56亿 拟募资4.38亿

雷递网 雷建平 12月20日江苏飞宇医药科技股份有限公司&#xff08;简称&#xff1a;“飞宇医药”&#xff09;日前递交招股书&#xff0c;准备在深交所创业板上市。飞宇医药计划募资4.38亿元&#xff0c;其中&#xff0c;1.79亿元用于年产6000吨侧链及6,000吨酰氯扩产项目&…

QT Qmake笔记

文章目录概述QT修改样式qmake概述pro文件常见配置项库引用和库路径指定QT创建动态库和使用&#xff08;重要&#xff09;小例子写动态库用动态库参考资料附录概述 本文记录一些学习QT过程中的笔记。 QT修改样式 styleSheet&#xff1a; background-image:url("/home/o…

大学生转行,毕业一年半,她是如何从工地走向互联网的?

如果专业与工作不匹配&#xff1f;如果觉得现有工作不适合自己&#xff1f;如果想转行&#xff1f;可以看一下她的成长故事。 领英18年数据显示&#xff0c;职场人第一份工作在职时间显著缩短&#xff0c;70后平均超过4年换一次工作&#xff0c;80后是3年半&#xff0c;90后是…

Bitmap64为什么比bitmap32慢

https://www.bilibili.com/video/BV1vU4y1q7KR/?spm_id_from333.788&vd_sourcefa36a95b3c3fa4f32dd400f8cabddeaf 原因跟 RoaringBitmap64 的实现有关&#xff0c;RoaringBitmap64 是由一系列 RoaringBitmap32 表示。实现方式有很多种&#xff0c;一种比较通用的做法用 ma…

【MyBatis】MyBatis Plus的使用

1.Mybatis-Plus 1.1 简介 MyBatis-Plus 是一个 Mybatis 增强版工具&#xff0c;在 MyBatis 上扩充了其他功能没有改变其基本功能&#xff0c;为了简化开发提交效率而存在。 官网文档地址&#xff1a;   https://mp.baomidou.com/guide/ MyBatis-Plus 特性&#xff1a;  …

非科班出身转行IT难吗?好找工作吗?

大家都知道&#xff0c;IT行业是出了名的高薪行业&#xff0c;很多传统行业/专业的小伙伴由于薪资低、就业机会少而有了想转行IT的想法。 他们通常有以下几个问题&#xff1a; 非计算机专业0基础能学会技术吗&#xff1f;非计算机专业如何转行到IT行业&#xff1f;非计算机专…

记录--可视化大屏-用threejs撸一个3d中国地图

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 不想看繁琐步骤的&#xff0c;可以直接去github下载项目&#xff0c;如果可以顺便来个star哈哈 本项目使用vue-cli创建&#xff0c;但不影响使用&#xff0c;主要绘制都已封装成类 1、使用geoJson绘制…

Java并发系列源码分析(四)--StampedLock

简介 ReentrantReadWriteLock是一个悲观的可重入的读写锁,而StampedLock既支持悲观锁也支持乐观锁但不支持锁的重入, 在ReentrantReadWriteLock下如果多个线程同时获取读锁的时候,获取写锁的线程就会被挂起进行等待,在StampedLock乐观锁下如果有线程加了写锁,其它读线程可以获…

英语不好能不能学好python?试试我的方法就知道了

这是本文的目录前言一、交互环境与print输出&#xff08;python编程常用单词&#xff09;二、字符串操作&#xff08;python编程常用单词&#xff09;三、重复\替换\转换\原始字符串&#xff08;python编程常用单词&#xff09;四、去除\查询\计数&#xff08;python编程常用单…

JavaWeb之Servelt学习01

目录 1.Servlet 1.1快速入门 1.2Servlet 执行原理 1.3Servlet执行方法 1.3.1Servlet中的生命周期方法 1.4注解配置 1.5.Servlet体系结构 1.6Servlet相关配置 1.Servlet 概念&#xff1a;运行在服务端的小程序 Servlet就是一个接口&#xff0c;定义了java类被浏览器访问到…

高速高精度半导体运动台设计(二)

高速高精运动平台的性能不仅与运动控制器、伺服驱动相关&#xff0c;也与电机本身的性能密切相关。如图 5-2 所示的运动平台采用了雅科贝思的直线电机&#xff0c;直接驱动负载&#xff0c;刚性高&#xff0c;响应快&#xff0c;同时选用了高性能多轴运动控制卡和 GTHD 系列高性…

【Java 数据结构】树和二叉树

篮球哥温馨提示&#xff1a;编程的同时不要忘记锻炼哦&#xff01;一棵倒立过来的树. 目录 1、什么是树&#xff1f; 1.1 简单认识树 1.2 树的概念 1.3 树的表示形式 2、二叉树 2.1 二叉树的概念 2.2 特殊的二叉树 2.3 二叉树的性质 2.4 二叉树性质相关习题 3、实…

uniapp 多商品sku组件v3版本

如果您正在寻找一款v3版本的多商品sku组件的话&#xff0c;那我想这款组件刚好可以满足各位。 先来简单看一眼效果图: 看起来是不是还不错&#xff0c;如果我告诉你还可以设置主题色会不会显得更加惊艳些&#xff0c;只需要按照数组格式将rgb的颜色传递给组件&#xff0c;…

智慧医疗中人工智能的7大应用|数据标注

从药物研发到预测肾脏疾病&#xff0c;人工智能在智慧医疗领域应用广泛。 人工智能在许多医学领域和专业中的应用正在成为现实。人工智能、机器学习、自然语言处理和深度学习使智慧医疗利益相关者和医疗专业人员能够更快、更准确地明确智慧医疗需求和解决方案&#xff0c;并依…

【WPF绑定2】 ComboBox SelectedValue复杂数据类型绑定

前言 这次绑定是一次非常痛苦的经历&#xff0c;因为SelectedValue总是不能生效&#xff01;我一度怀疑是wpf的Bug。其实还是自己没搞清楚。 在之前的一篇文章中&#xff1a; http://t.csdn.cn/A4W6Ahttp://t.csdn.cn/A4W6A我也写个ComboBox的绑定&#xff0c;但是当时没有指…

css实现两列/三列布局

文章目录css实现两列/三列布局两列布局三列布局css实现两列/三列布局 两列布局 第一种方式&#xff1a;浮动实现 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible"…