行为设计模式 -责任链模式- JAVA

news2024/11/25 4:37:41

责任链设计模式

    • 一 .简介
    • 二. 案例
      • 2.1 抽象处理者(Handler)角色
      • 2.2 具体处理者(ConcreteHandler)角色
      • 2.3 测试
    • 三. 结论
      • 3.1 优缺点
      • 3.2 示例
      • 3.3 要点

前言
这是我在这个网站整理的笔记,有错误的地方请指出,关注我,接下来还会持续更新。

作者:神的孩子都在歌唱

一 .简介

百度百科:责任链模式是一种行为设计模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织分配责任。

个人理解: 通过责任链方式可以找到能够处理客户端请求的对象。感觉就跟Switch 或者try-catch 一样,当前不匹配就继续往下匹配。

责任链模式涉及到的角色如下所示:

● **抽象处理者(Handler)角色:**定义出一个处理请求的接口。如果需要,接口可以定义 出一个方法以设定和返回对下家的引用。这个角色通常由一个Java抽象类或者Java接口实现。Handler类的聚合关系给出了具体子类对下家的引用,抽象方法handleRequest()规范了子类处理请求的操作。

● **具体处理者(ConcreteHandler)角色:**具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具体处理者可以访问下家。

二. 案例

网上看了很多案例,感觉ATM取款机这个案例最容易理解。需求是让用户输入一个金额数(amount),然后ATM机会将输入的金额数从大到小(能够分配的纸币类型是100元 20 元 10元)进行分配。如果用户输入的金额不是10的倍数,就抛出错误。

image-20240604171326864

其实这个实现起来很简单,不过为了将每种类型的纸币进行解耦,所以需要使用责任链方式去解决

2.1 抽象处理者(Handler)角色

定义分配的处理链接口

/**
 * @author chenyunzhi
 * @date 2024/6/4 16:27
 * @Description 分配的处理链接口
 */
public interface DispenseChain {

    /**
     * 要执行的下一个链(对象)
     */
    void setNextChain(DispenseChain nextChain);


    /**
     * 执行分配的方法
     */
    void dispense(Integer amount);
}

2.2 具体处理者(ConcreteHandler)角色

定义每种纸币的对象

Yuan100Dispenser

/**
 * @author chenyunzhi
 * @date 2024/6/4 16:30
 * @Description
 */
public class Yuan100Dispenser implements DispenseChain{

    private DispenseChain dispenseChain;
    @Override
    public void setNextChain(DispenseChain nextChain) {
        this.dispenseChain = nextChain;
    }

    @Override
    public void dispense(Integer amount) {
        if (amount >= 100) {
            int num = amount / 100;
            int remainder = amount % 100;
            System.out.println("分配了" + num + "张100元");
            // 进入下一个分配
            if (remainder != 0) {
                this.dispenseChain.dispense(remainder);
            }
        } else {
            this.dispenseChain.dispense(amount);
        }
    }
}

Yuan20Dispenser

/**
 * @author chenyunzhi
 * @date 2024/6/4 16:30
 * @Description
 */
public class Yuan20Dispenser implements DispenseChain{

    private DispenseChain dispenseChain;
    @Override
    public void setNextChain(DispenseChain nextChain) {
        this.dispenseChain = nextChain;
    }

    @Override
    public void dispense(Integer amount) {
        if (amount >= 20) {
            int num = amount / 20;
            int remainder = amount % 20;
            System.out.println("分配了" + num + "张20元");
            // 进入下一个分配
            if (remainder != 0) {
                this.dispenseChain.dispense(remainder);
            }
        } else {
            this.dispenseChain.dispense(amount);
        }
    }
}

Yuan10Dispenser

/**
 * @author chenyunzhi
 * @date 2024/6/4 16:30
 * @Description
 */
public class Yuan10Dispenser implements DispenseChain{

    private DispenseChain dispenseChain;
    @Override
    public void setNextChain(DispenseChain nextChain) {
        this.dispenseChain = nextChain;
    }

    @Override
    public void dispense(Integer amount) {
        if (amount >= 10) {
            int num = amount / 10;
            int remainder = amount % 10;
            System.out.println("分配了" + num + "张10元");
            // 进入下一个分配
            if (remainder != 0) {
                this.dispenseChain.dispense(remainder);
            }
        } else {
            this.dispenseChain.dispense(amount);
        }
    }
}

2.3 测试

这一步我们将三种纸币连接起来,创建链进行测试

/**
 * @author chenyunzhi
 * @date 2024/6/4 16:48
 * @Description 测试
 */
public class ChainOfResponsibilityPatternTest {


    private DispenseChain chain;
    /**
     * 初始化atm分配链
     */
    public  ChainOfResponsibilityPatternTest() {
        this.chain = new Yuan100Dispenser();
        Yuan20Dispenser yuan20Dispenser = new Yuan20Dispenser();
        Yuan10Dispenser yuan10Dispenser = new Yuan10Dispenser();

        chain.setNextChain(yuan20Dispenser);
        yuan20Dispenser.setNextChain(yuan10Dispenser);
    }
    public static void main(String[] args) {
        ChainOfResponsibilityPatternTest patternTest = new ChainOfResponsibilityPatternTest();
        for (int i=0; i<3; i++){
            System.out.println("----------输入领取金额-----------");
            Scanner scanner = new Scanner(System.in);
            int amount = scanner.nextInt();
            if (amount % 10 != 0) {
                System.out.println("需要输入10的倍数的金额");
                continue;
            }
            patternTest.chain.dispense(amount);
            System.out.println("----------分配结束-----------");
        }

    }
   
}

image-20240604171106716

通过上面的组装链,就能够将atm的需求实现了。

三. 结论

3.1 优缺点

1,优点:

  • 降低了对象之间的耦合度: 该模式降低了请求发送者和接收者的耦合度。

  • 增强了系统的可扩展性:可以根据需要增加新的请求处理类,满足开闭原则。

  • 增强了给对象指派职责的灵活性:当工作流程发生变化,可以动态地改变链内的成员或者修改它们的次序,也可动态地新增或者删除责任。

  • 责任链简化了对象之间的连接:一个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句。

  • 责任分担:每个类只需要处理自己该处理的工作,不能处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。

2,缺点:

  • 不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
  • 对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
  • 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。

3.2 示例

  • java.util.logging.Logger#log()
  • javax.servlet.Filter#doFilter()

3.3 要点

  1. 责任链设计模式可以很好地实现失去耦合,但如果大多数代码在所有实现中都是通用的,那么它会带来大量实现类和维护问题的权衡。
  2. 客户端不知道链的哪一部分将处理请求,它会将请求发送到链中的第一个对象

作者:神的孩子都在歌唱

本人博客:https://blog.csdn.net/weixin_46654114

转载说明:务必注明来源,附带本人博客连接。

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

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

相关文章

xxl-job java.sql.SQLException: interrupt问题排查

近期生产环境固定凌晨报错&#xff0c;提示 ConnectionManager [Thread-23069] getWriteConnection db:***,pattern: error, jdbcUrl: jdbc:mysql://***:3306/***?connectTimeout3000&socketTimeout180000&autoReconnecttrue&zeroDateTimeBehaviorCONVERT_TO_NUL…

面试域——岗位职责以及工作流程

摘要 介绍互联网岗位的职责以及开发流程。在岗位职责方面&#xff0c;详细阐述了产品经理、前端开发工程师、后端开发工程师、测试工程师、运维工程师等的具体工作内容。产品经理负责需求收集、产品规划等&#xff1b;前端专注界面开发与交互&#xff1b;后端涉及系统架构与业…

本地缓存库分析(一):golang-lru

文章目录 本地缓存概览golang-lru标准lrulru的操作PutGet 2q&#xff1a;冷热分离lruPutGet expirable_lru&#xff1a;支持过期时间的lruPutGet过期 总结 本地缓存概览 在业务中&#xff0c;一般会将极高频访问的数据缓存到本地。以减少网络IO的开销&#xff0c;下游服务的压…

【OpenAI】第五节(图像生成)利用 OpenAI 的 DALL·E 实现自动化图像生成:从文本到图像的完整教程

引言 OpenAI 推出的 DALLE 工具因其能够生成令人惊叹的艺术作品而备受瞩目。DALLE 不仅能够生成静态图像&#xff0c;还能根据用户的需求进行风格化处理&#xff0c;创造出独特的艺术作品。通过 OpenAI 的 API&#xff0c;你可以轻松将 DALLE 的强大功能集成到你的 Python 程序…

基于SSM的智慧篮球馆预约系统

前言 近些年&#xff0c;随着中国经济发展&#xff0c;人民的生活质量逐渐提高&#xff0c;对网络的依赖性越来越高&#xff0c;通过网络处理的事务越来越多。随着智慧篮球馆预约的常态化&#xff0c;如果依然采用传统的管理方式&#xff0c;将会为工作人员带来庞大的工作量&a…

Linux中C/C++程序编译过程与动静态链接库概述

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

qt QMainWindow详解

一、概述 QMainWindow继承自QWidget&#xff0c;并提供了一个预定义的布局&#xff0c;将窗口分成了菜单栏、工具栏、状态栏和中央部件区域。这些区域共同构成了一个功能丰富的主窗口&#xff0c;使得应用程序的开发更加简单和高效。 二、QMainWindow的常用组件及功能 菜单栏&…

【Java网络编程】从套接字(Socket)概念到UDP与TCP套接字编程

目录 网络编程 1.socket套接字 2.udp数据报套接字编程 DatagramSocket API DatagramPacket API Java基于UDP实现客户端-服务器代码实例 3.tcp流套接字编程 ServerSocket API Socket API TCP中的长短连接 Java基于TCP客户端-服务器代码实例 网络编程 1.socket套接字 S…

云对象存储进阶

《使用Minio搭建文件服务器》一文对minio作了简单的介绍&#xff0c;本文为进阶学习。 1.对象存储产品介绍 目前市场上流行各种对象存储服务&#xff0c;诸如以下&#xff1a; Amazon S3&#xff1a;亚马逊提供的服务&#xff0c; 是市场上最成熟的产品&#xff0c;拥有最大的…

ATom:2016-2018 年沿飞行轨迹的 CAM-chem/CESM2 模型输出

目录 简介 摘要 代码 引用 网址推荐 知识星球 机器学习 ATom: CAM-chem/CESM2 Model Outputs Along Flight Tracks, 2016-2018 ATom&#xff1a;2016-2018 年沿飞行轨迹的 CAM-chem/CESM2 模型输出 简介 该数据集包含沿 ATom 飞行轨迹的 CAM-chem&#xff08;带化学的…

[ARM-2D 专题]5 MDK编译器一个旧版本-Ofast优化bug的问题及解决办法

最近开始大量基于ARM-2D开发应用项目&#xff0c;为了达到最佳性能&#xff0c;我们使用了编译器的许多特殊技能&#xff0c;其中就包含了-Ofast优化&#xff0c;很不幸&#xff0c;一不小心踩坑了。 案发情况如下&#xff1a; 使用的MDK版本5.36&#xff0c;编译器6.16 优化选…

在GeoTools中的Shapefile属性表读取效率之Shp与Dbf对比

目录 前言 一、POI测试数据简介 1、选用的POI数据 2、关于数据的属性数据 二、属性数据读取的两种方式实现 1、基于DbaseFileReader的读取 2、基于SimpleFeatureSource的读取 三、实际运行对比 1、内存和CPU占用情况 2、运行耗时情况 四、总结 前言 众所周知&#x…

【深度学习中的注意力机制10】11种主流注意力机制112个创新研究paper+代码——交叉注意力(Cross-Attention)

【深度学习中的注意力机制10】11种主流注意力机制112个创新研究paper代码——交叉注意力&#xff08;Cross-Attention&#xff09; 【深度学习中的注意力机制10】11种主流注意力机制112个创新研究paper代码——交叉注意力&#xff08;Cross-Attention&#xff09; 文章目录 【…

‌Spring MVC的主要组件有哪些?

前言 SpringMVC的核心组件包括DispatcherServlet、Controller、HandlerMapping、HandlerAdapter、ViewResolver、ModelAndView等&#xff0c;它们协同工作以支持基于MVC架构的Web应用程序开发。这些组件使得开发人员能够以一种声明式和模块化的方式构建Web应用程序&#xff0c…

小程序开发实战:PDF转换为图片工具开发

目录 一、开发思路 1.1 申请微信小程序 1.2 编写后端接口 1.3 后端接口部署 1.4 微信小程序前端页面开发 1.5 运行效果 1.6 小程序部署上线 今天给大家分享小程序开发系列&#xff0c;PDF转换为图片工具的开发实战&#xff0c;感兴趣的朋友可以一起来学习一下&#xff01…

ECharts饼图-基础南丁格尔玫瑰图,附视频讲解与代码下载

引言&#xff1a; 在数据可视化的世界里&#xff0c;ECharts凭借其丰富的图表类型和强大的配置能力&#xff0c;成为了众多开发者的首选。今天&#xff0c;我将带大家一起实现一个饼图图表&#xff0c;通过该图表我们可以直观地展示和分析数据。此外&#xff0c;我还将提供详…

一、在cubemx下RTC配置调试实例测试

一、rtc的时钟有lse提供。 二、选择rtc唤醒与闹钟功能 内部参数介绍 闹钟配置 在配置时间时&#xff0c;注意将时间信息存储起来&#xff0c;防止复位后时间重新配置。 if(HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR0)! 0x55AA)//判断标志位是否配置过&#xff0c;没有则进…

qt EventFilter用途详解

一、概述 EventFilter是QObject类的一个事件过滤器&#xff0c;当使用installEventFilter方法为某个对象安装事件过滤器时&#xff0c;该对象的eventFilter函数就会被调用。通过重写eventFilter方法&#xff0c;开发者可以在事件处理过程中进行拦截和处理&#xff0c;实现对事…

WSL2 Ubuntu22.04编译安装LLVM

前提 这两天因为工作需要&#xff0c;要编译一个Debug版本的llvm。这里对编译安装过程进行一个简单的记录&#xff0c;同时也记录下这个过程中遇到的几个问题。 下载源码并编译 有关llvm编译安装的官方文档在这里。 从git仓库clone llvm的源码。 git clone https://github.c…

FPGA搭建PCIE3.0通信架构简单读写测试,基于XDMA中断模式,提供3套工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的PCIE方案本博客方案的PCIE2.0版本 3、PCIE基础知识4、工程详细设计方案工程设计原理框图XDMA配置及使用XDMA中断模块数据缓存架构用户逻辑Windows版本XDMA驱动安装Linux版本XDMA驱动安装测试应用程序工程源码架构PCIE上板…