设计模式之职责链模式

1. 职责链模式(Chain of Responsibility Pattern)

        在职责链模式中,多个处理器依次处理同一个请求。一个请求先经过 A 处理器处理,然后再把请求传递给 B 处理器,B处理器处理完后再传递给 C 处理器,以此类推,形成一个链条。链条上的每个处理器各自承担各自的处理职责,所以叫作职责链模式。

1.1. 模式架构

  • 抽象处理者(Handler):定义一个处理请求的接口,包含抽象处理方法一个后继连接(链上的每个处理者都有一个成员变量来保存对于下一处理者的引用) 。
  • 具体处理者(Concrete Handler):实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
  • 请求者(Client):创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。

1.2. 示例实现代码

        Trouble类是表示发生问题的类,number是问题编号。通过getNumber来获取问题编号。

        问题的大小从升序排序为:1 < 2 < 3 < 4

        处理者处理问题的能力升序排序为:HandlerA < HandlerB < HandlerC < HandlerD

public class Trouble {
    private String number;//问题编号

    public Trouble(String number) {
        this.number = number;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    @Override
    public String toString() {
        return "Trouble{" +
                "number='" + number + '\'' +
                '}';
    }
}

抽象处理者(Handler):

Handler

public abstract class Handler{
    //处理器执行链路
    protected Handler successor = null;

    //设置下一个处理请求的处理者对象
    public void setSuccessor(Handler successor){
        this.successor = successor;
    }

    //处理的方法,具体处理者需根据不同需求进行实现
    public abstract void handle(Trouble trouble);
}

具体处理者(Concrete Handler):

HandlerA

public class HandlerA extends Handler {
   //具体处理者的实现方法
    @Override
    public void handle(Trouble trouble) {
        System.out.print("HandlerA 执行代码逻辑! 处理: " +
                trouble.getNumber());
        trouble.setNumber(trouble.getNumber().replace("1", ""));
        System.out.println(",处理完的结果为:" + trouble.getNumber());
        if (successor != null) {
            successor.handle(trouble);
        }else {
            System.out.println("执行终止");
        }
    }
}

HandlerB

public class HandlerB extends Handler {
    //具体处理者的实现方法
    @Override
    public void handle(Trouble trouble) {
        System.out.print("HandlerB 执行代码逻辑! 处理: " +
                trouble.getNumber());
        trouble.setNumber(trouble.getNumber().replace("2", ""));
        System.out.println(",处理完的结果为:" + trouble.getNumber());
        if (successor != null) {
            successor.handle(trouble);
        }else {
            System.out.println("执行终止");
        }
    }
}

HandlerC

public class HandlerC extends Handler {
   //具体处理者的实现方法
    @Override
    public void handle(Trouble trouble) {
        System.out.print("HandlerC 执行代码逻辑! 处理: " +
                trouble.getNumber());
        trouble.setNumber(trouble.getNumber().replace("3", ""));
        System.out.println(",处理完的结果为:" + trouble.getNumber());
        if (successor != null) {
            successor.handle(trouble);
        }else {
            System.out.println("执行终止");
        }
    }
}

HandlerD

public class HandlerD extends Handler {
   //具体处理者的实现方法
    @Override
    public void handle(Trouble trouble) {
        System.out.print("HandlerD 执行代码逻辑! 处理: " +
                trouble.getNumber());
        trouble.setNumber(trouble.getNumber());
        System.out.println(",处理完的结果为:" + trouble.getNumber());
        if (successor != null) {
            successor.handle(trouble);
        }else {
            System.out.println("执行终止");
        }
    }
}

请求者(Client):

public class Client {
    public static void main(String[] args) {
        //包含1234的问题
        Trouble trouble = new Trouble("1234");
        //包含123的问题
        Trouble trouble2 = new Trouble("123");
        
        Handler h1 = new HandlerA();
        Handler h2 = new HandlerB();
        Handler h3 = new HandlerC();
        //设置处理器执行链路
        h1.setSuccessor(h2);
        h2.setSuccessor(h3);
        //执行
        h1.handle(trouble);
    }
}

执行结果:

HandlerA 执行代码逻辑! 处理: 1234,处理完的结果为:234

HandlerB 执行代码逻辑! 处理: 234,处理完的结果为:34

HandlerC 执行代码逻辑! 处理: 34,处理完的结果为:4

执行终止

        在以上示例代码中,Handler抽象类定义了处理的抽象方法和后续的执行连接处理对象,而HandlerA~D是对应不同的具体处理类,每个类可以解决不同级别的问题,请求者可以设置执行链路,当一个含有不同等级的问题要处理时,会根据执行链路进行执行,若当前处理类无法处理该问题,则让下一个处理对象判断是否能处理,执行全部处理完毕。

1.3. 优缺点

优点

  • 降低耦合度:请求者不需要知道是哪个具体的处理者处理请求,降低了发送者和接收者之间的耦合度。
  • 灵活性增强:可以动态地增加或修改处理请求的链条,更容易地根据需要改变处理流程。
  • 简化对象:每个具体处理者只需关注自己责任范围内的处理逻辑,符合单一职责原则。

缺点

  • 请求不一定被处理:如果请求到达链条末端仍然没有处理者能够处理,可能会导致请求未被处理的情况。
  • 性能问题:请求可能会经过多个处理者才能被处理,特别是在链条较长时,可能会影响性能。
  • 调试复杂:链条中每个具体处理者的执行顺序不确定,难以调试。

在生活中比较常见的应用模式有:

1、在运行时需要动态使用多个关联对象来处理同一次请求时,比如各种流程执行:请假流程、员工入职流程。

2、需要动态更换处理对象时。比如,工单处理系统、网关 API 过滤规则系统等。

3、电商网站活动方式,一般分为满减送、限时折扣、包邮活动,拼团等可以采用策略模式

        职责链模式常被用在框架开发中,用来实现框架的过滤器、拦截器功能,让框架的使用者在不修改源码的情况下,添加新的过滤拦截功能。

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

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

相关文章

【Android组件】封装加载弹框

&#x1f4d6;封装加载弹框 ✅1. 构造LoadingDialog✅2. 调用LoadingDialog 效果&#xff1a; ✅1. 构造LoadingDialog 构造LoadingDialog类涉及到设计模式中的建造者模式&#xff0c;进行链式调用&#xff0c;注重的是构建的过程&#xff0c;设置需要的属性。 步骤一&#x…

基于考研题库小程序V2.0实现倒计时功能板块和超时判错功能

V2.0 需求沟通 需求分析 计时模块 3.1.1、功能描述←计时模块用于做题过程中对每一题的作答进行30秒倒计时&#xff0c;超时直接判错&#xff0c;同时将总用时显示在界面上;记录每次做题的总用时。 3.1.2、接口描述←与判定模块的接口为超时判定&#xff0c;若单题用时超过 …

C++:缺省参数|函数重载|引用|const引用

欢迎来到HarperLee的学习笔记&#xff01; 博主主页传送门&#xff1a;HarperLee的博客主页 想要一起进步的uu可以来后台找我哦&#xff01; 一、缺省参数 1.1 缺省参数的定义 缺省参数&#xff1a;是声明或定义函数时为函数的参数指定⼀个缺省值。在调用该函数时&#xff0c;…

MYSQL数据库建表规则及注意事项

数据类型以及应用场景 数值类型 TINYINT&#xff1a;使用在 0~1 SMALLINT&#xff1a;使用在2~10 INT&#xff1a;常用 BIGINT&#xff1a;使用在用户ID等更大范围的整数 DECIMAL&#xff1a;用于存储精确的小数。常用于需要高精度计算的场景&#xff0c;如金融数据处理。 日期…

【UE5.3】笔记10-时间轴的使用

时间轴 右键--Add Timeline(在最下面) --> 双击进入时间轴的编辑界面&#xff1a; 左上角可以添加不同类型的轨道&#xff0c;可以自定义轨道的长度&#xff0c;单位秒&#xff0c;一次可以添加多个 可以通过右键添加关键帧&#xff0c;快捷键&#xff1a;shift鼠标左键按…

JMH325【剑侠情缘3】第2版80级橙武网游单机更稳定亲测视频安装教学更新整合收集各类修改教学补丁兴趣可以慢慢探索

资源介绍&#xff1a; 是否需要虚拟机&#xff1a;是 文件大小&#xff1a;压缩包约14G 支持系统&#xff1a;win10、win11 硬件需求&#xff1a;运行内存8G 4核及以上CPU独立显卡 下载方式&#xff1a;百度网盘 任务修复&#xff1a; 1&#xff0c;掌门任务&#xff08…

MMII 的多模态医学图像交互框架:更直观地理解人体解剖结构和疾病

医生在诊断和治疗过程中依赖于人体解剖图像&#xff0c;如磁共振成像&#xff08;MRI&#xff09;&#xff0c;难以全面捕捉人体组织的复杂性&#xff0c;例如组织之间的空间关系、质地、大小等。然而&#xff0c;实时感知有关患者解剖结构和疾病的多模态信息对于医疗程序的成功…

在mysql中delete和truncated的相同点和区别点

相同点 删除数据&#xff1a;两者都会删除表中的数据。影响数据&#xff1a;两者都不删除表结构&#xff0c;只影响表中的数据。 区别点 操作方式&#xff1a; DELETE&#xff1a;逐行删除数据&#xff0c;可以使用 WHERE 子句来指定删除的条件。如果不加 WHERE 子句&#…

R包:ggsci期刊配色

介绍 不同期刊配色大多数时候不一样&#xff0c;为了更好符合期刊图片颜色的配色&#xff0c;有人开发了ggsci这个R包。它提供以下函数&#xff1a; scale_color_palname() scale_fill_palname() 对应不同期刊的color和fill函数。 导入数据R包 library("ggsci")…

LAZYNVIM学习使用笔记

文章目录 1. 前言VIM的模式快捷键参考 1. 前言 习惯使用vscode进行代码编辑&#xff0c;无意中刷到lazynvim&#xff0c;感觉功能强大&#xff0c;于是下载、安装&#xff0c;学习使用一下&#xff0c;本篇主要记录学习使用lazynvim的一些要点&#xff0c;防止遗忘。 持续更新…

Unity 打包的安卓APK在模拟器运行一会卡死

Unity 安卓APK模拟器运行一会卡死 如题&#xff0c;unity在模拟器上运行安卓apk挂机一会就卡死&#xff0c;在真机上没问题。因为打包时勾选了这个帧率优化选项&#xff0c;2019.2之后的功能&#xff0c;最坑的时打包时默认勾选&#xff0c;所以使用这个版本打包时&#xff0c…

文献阅读(1)——深度强化学习求解车辆路径问题的研究综述

doi&#xff1a; 10.3778/j.issn.1002-8331.2210-0153 深度强化学习求解车辆路径问题的研究综述 (ceaj.org) 组合最优化问题&#xff08; combinatorial optimization problem&#xff0c; COP &#xff09; 日常生活中常见的 COP 问题有旅行商问题&#xff08;traveling sale…

微调Qwen2大语言模型加入领域知识

这里写自定义目录标题 试用Qwen2做推理安装LLaMA-Factory使用自有数据集微调Qwen2验证微调效果 试用Qwen2做推理 参考&#xff1a;https://qwen.readthedocs.io/en/latest/getting_started/quickstart.html from transformers import AutoModelForCausalLM, AutoTokenizer de…

NI 5G大规模MIMO测试台:将理论变为现实

目录 概览引言MIMO原型验证系统MIMO原型验证系统硬件LabVIEW通信系统设计套件&#xff08;简称LabVIEW Communications&#xff09;CPU开发代码FPGA代码开发硬件和软件紧密集成 LabVIEW Communications MIMO应用框架MIMO应用框架特性单用户MIMO和多用户MIMO基站和移动站天线数量…

作业/数据结构/2023/7/10

1.实现单向链表队列的&#xff0c;创建&#xff0c;入队&#xff0c;出队&#xff0c;遍历&#xff0c;长度&#xff0c;销毁。 main.c #include "head.h"int main(int argc, const char *argv[]) {//创建链式队列queue_ptr QLcreate_queue();//入栈push(QL, 1000)…

OpenGL3.3_C++_Windows(29)

Demo exposure 0.1f exposure 5.0f HDR色调映射 问题&#xff1a;有多个亮光源使这些数值总和超过了1.0&#xff0c;颜色值会被约束在1.0&#xff0c;从而导致场景混成一片&#xff0c;难以分辨&#xff1a;色调映射&#xff1a;用更大范围的颜色值渲染从而获取大范围的黑暗…

手搓前端day1

断断续续的学了些前端&#xff0c;今天开始写写代码&#xff0c;就当是记录一下自己前端的成长过程 效果&#xff1a; 写了点css&#xff0c;实现了简单的前端页面的跳转 文件目录 代码如下&#xff1a; styles.css body{margin: 0;padding: 0;}header{background-color: bl…

从0-1搭建一个web项目(路由目录分析)详解

本章分析vue路由目录文件详解 ObJack-Admin一款基于 Vue3.3、TypeScript、Vite3、Pinia、Element-Plus 开源的后台管理框架。在一定程度上节省您的开发效率。另外本项目还封装了一些常用组件、hooks、指令、动态路由、按钮级别权限控制等功能。感兴趣的小伙伴可以访问源码点个赞…

vue前端实现导出页面为word(两种方法)

将vue页面导出为word文档&#xff0c;不用写模板&#xff0c;直接导出即可。 第一种方法(简单版) 第一步&#xff1a;安装所需依赖 npm install html-docx-js -S npm install file-saver -S第二步&#xff1a;创建容器&#xff0c;页面使用方法 注意&#xff1a;在当前页面引…

对于多个表多个字段进行查询、F12查看网页的返回数据帮助开发、数据库的各种查询方式(多对多、多表查询、子查询等)。

对于多个表多个字段进行查询、F12查看网页的返回数据帮助开发、数据库的各种查询方式&#xff08;多对多、多表查询、子查询等&#xff09;。 一、 前端界面需要展现多个表的其中几个数据的多表查询。1. 三个表查询其中字段返回&#xff1a;&#xff08;用一下sql语句&#xff…