设计模式系列/ 职责链模式

news2024/11/24 9:20:15

必读

本篇主要分析设计模式之 职责链模式
什么人适合学习本章节呢。

  • 从未接触过设计模式的同学
  • 有n年工作经验 && 对职责链模式不了解的同学

1. 职责链模式意识形态

设计模式充斥着我们开发过程中的方方面面,责任链模式也是如此。也许你用到了设计模式,只是不知道这是哪种设计模式,甚至不知道这是设计模式。
所以我们今天的目的也是为了解开谜底 的。

在这里插入图片描述

我们可以将职责链的部分, 理解为相连的链表。每个接收者 只关心自己后面的部分。如果依次顺序执行以后会执行到最后的。

在这里插入图片描述

通过上述截图我们可以清晰的看到:每个接收者都可以直接引用到下一个接收者,但是也有可能下一个接收者为null。
所以对于职责链而言,只需要关心下一个接收者就够了。

但是不可能想干啥就干啥,一定是在一个规范下进行定义的。
在这里插入图片描述

通过以上的截图我们分析得到,职责链中有几种角色是必须的:

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

以上角色的划分 比较符合我们对职责链的期望。比如:我们使用变量successor 来保存下一个接收者的引用。
好了 废话不错说了,我们来列举一个小小的案例。

2. 小小的案例

定义抽象类,用来指定行为规范。

public abstract class Handler {
  protected Handler next;
  
  public void setNext(Handler next) {
    this.next = next;
  }
  
  public abstract void handleRequest(String request);
}

行为实现A

public class HandleImplA extends Handler {
  @Override
  public void handleRequest(String request) {
    System.out.println("replace str A");
    request = request.replace("A", "");
    
    if (this.next != null) {
      this.next.handleRequest(request);
    }
  }
}

行为实现B

public class HandleImplB extends Handler {
  @Override
  public void handleRequest(String request) {
    System.out.println("replace str B");
    request = request.replace("B", "");
    
    if (this.next != null) {
      this.next.handleRequest(request);
    }
  }
}

client 端 发送链请求

public class Test001 {
  
  @Test
  public void test01() {
    Handler handleImplA = new HandleImplA();
    Handler handleImplB = new HandleImplB();
    
    handleImplA.setNext(handleImplB);
    handleImplA.handleRequest("ABC");
  }
}

在这里插入图片描述

通过上述案例可以分析得知:

  • 我们每个都需要实现抽象类Handler, 因为抽象类中规范了我们的行为,例如:引用了下一个接收者,以及必须定义事件处理方法。
  • 每个具体的类 都需要实现这个抽象类
  • 所以对于每个接收者来说,我们只需要关心下一个接收者是否能够执行就够了。

3. 业务场景中案例

3.1 场景1

public class AInvalidPathFilter implements Filter {
  
  @Override
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    filterChain.doFilter(servletRequest, servletResponse);
  }
}

无论是我们Java开发中的拦截器,还是过滤器 都是职责链模式的一种体现。核心的逻辑是不变化,只不过是代码的实现方式发生了变化。

3.2 场景2

不知道大家是否知道前端中的Koa框架。个人拙见 其实Koa的链式方法调用 也是一种职责链模式的体现,让我们一起来分析下。

// ------------------- 定义
import  Koa from "koa"
import Router from "koa-router"
import bodyParser from "koa-bodyparser"

const app = new Koa()
app.use(Router())
app.use(bodyParser())


// ------------------- 使用
// 例如 Router

const Router = () => (ctx, next) => {
  // 手动执行next 方法才会执行下一步
  next();
}


// ------------------- 内部原理
const middlewares = []; // 所有的中间件
const ctx = {} // 表示koa上下文
const use = (index) => {
  const fn = middlewares[index];
  if (!fn) return;
  fn(ctx, () => use(index + 1));
}

// 第一次执行
use(0);

上述代码就是最简单的Koa的实现原理,让我们一起来分析下。

  1. 在我们的职责链模式的分配中,某一个接收者总是保留下一个接收者的引用,方便我们使用的时候调用。其实在Koa中也是如此,虽然实现不像Java中那样,但是使用数组middlewares 将每个插件保存,而且是顺序保存。
  2. 在职责链模式中如果想让整个链顺序执行,前一个接收者必须调用后一个接收者的引用方法。而在Koa中我们通过next进行关联。调用next才会调用下一个插件。

总体分析而言,个人感觉Koa中链式调用也是职责链模式一种体现。

4. 使用场景 以及缺点:

4.1 场景

  1. 在运行时需要动态使用多个关联对象来处理同一次请求时。比如,请假流程、员工入职流程、编译打包发布上线流程等
  2. 不想让使用者知道具体的处理逻辑时。比如,做权限校验的登录拦截器
  3. 需要动态更换处理对象时。比如,工单处理系统、网关 API 过滤规则系统等
  4. 职责链模式常被用在框架开发中,用来实现框架的过滤器、拦截器功能,让框架的使用者在不修改源码的情况下,添加新的过滤拦截功能

4.2 缺点

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

5. 结束

对职责链模式分下大致就这样。上述的分析来自于源码实际案例 以及个人对模式理解,如果有何不对的地方欢迎评论区指正。

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

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

相关文章

ElasticSearch-文档查询

目录 一、查询某个索引下的全部文档 二、根据查询条件查询文档 三、分页查询 四、查询指定返回的字段 五、排序 六、多条件查询 七、范围查询 八、全文检索与完全匹 一、查询某个索引下的全部文档 语法: GET /索引名称/_search {"query": {&quo…

[BJDCTF2020]Easy MD51

拿到题目后就一个空白页面,没啥特别的东西,传入参数也没啥变化 在查看源码无果后在响应头的找到了一份隐藏信息,应该就是页面对应的后端代码,我们提交的数据就是变量$pass的值 PHP中的MD5函数的意思是,将$pass变量的值…

LitCTF2023-部分Reserve复现

目录 一:[LitCTF 2023]snake pyc文件magic修复: pycdc工具转pyc文件为py文件: [LitCTF 2023]enbase64 [LitCTF 2023]ez_XOR [LitCTF 2023]For Aiur 在python38环境中将exe文件反编译为pyc文件 pycdc使用: [LitCTF 2023]程…

iptables防火墙1

iptables防火墙 iptables概述 Linux 系统的防火墙 :IP信息包过滤系统,它实际上由两个组件netfilter 和 iptables组成。 主要工作在网络层,针对IP数据包。体现在对包内的IP地址、端口、协议等信息的处理上。 netfilter/iptables 关系&#xf…

ADC模数转换器

目录 逐次逼近型ADC 原理图 ADC基本框图​编辑 输入通道 ​编辑 转换模式 ADC触发控制​编辑 数据对齐 ​编辑 采样时间 校准 硬件电路 来源b站江科大stm32入门教程 逐次逼近型ADC 原理图 规则组最好要和DMA一起使用 ADDCLK来自ADC预分频器 ,根据下图看出&…

OpenGL之绘制三角形

目录 OpenGL绘制图形的流程 标准化设备坐标 VAO和VBO VBO(顶点缓冲对象) VBO(顶点缓冲对象)创建流程 VAO(顶点数组对象) 绘制三角形 ​编辑给三角形添加颜色 顶点着色器 片段着色器 编译着色器 使用着色器为三角形添加颜色 OpenGL绘制图形的流程 在OpenGL中&…

二、Django REST Framework (DRF)序列化反序列化

参考: 为什么要学DRF和什么是REST API | 大江狗的博客 上一章: 一、Django REST Framework (DRF)& RESTful 风格api_做测试的喵酱的博客-CSDN博客 一、DRF框架介绍 1.1 介绍 Django REST Framework (DRF)这个神器我们可以快速开发出优秀而且…

基于SpringBoot的网吧管理系统的设计与实现

背景 随着信息技术和网络技术的飞速发展,人类已进入全新信息化时代,传统管理技术已无法高效,便捷地管理信息。为了迎合时代需求,优化管理效率,各种各样的管理系统应运而生,各行各业相继进入信息管理时代&a…

ICR-预测三种医学状况 #$60,000 #Kaggle

CompHub[1] 实时聚合多平台的数据类(Kaggle、天池…)和OJ类(Leetcode、牛客…)比赛。本账号会推送最新的比赛消息,欢迎关注! 以下信息由AI辅助创作,仅供参考 比赛名称 ICR - Identifying Age-Related Conditions[2] (见文末阅读原…

chatgpt赋能Python-pythonforrange

Python中的Range函数 在Python编程语言中,range()是一个用于生成一系列数字的函数。它可以接受1至3个整型参数:起始值、终止值和步长。生成的数字包括起始值,但不包括终止值。步长默认为1。 Range函数的语法 Python中range()函数的常规语法…

C++视角下的Qt按钮:从基础应用到高级定制

C视角下的Qt按钮:从基础应用到高级定制 一、Qt按钮基础 (Qt Button Basics)1.1 Qt按钮的定义与创建 (Definition and Creation of Qt Buttons)1.2 Qt按钮的属性 (Properties of Qt Buttons)文本 (Text)图标 (Icon)大小 (Size)样式 (Style)是否可用 (Enabled) 1.3 Qt…

Java【TCP 协议3】提高效率的五大机制

文章目录 前言一、滑动窗口与高速重传1, 什么是滑动窗口2, 什么是高速重传2.1, ack 丢包2.2, 数据丢包 二、流量控制1, 什么是流量控制 三、拥塞控制1, 什么是拥塞控制 四、延迟应答1, 什么是延迟应答 五、捎带应答1, 什么是捎带应答 总结 前言 各位读者好, 我是小陈, 这是我的…

JavaScript实现1-100之间所有的素数的代码

以下为实现1-100之间所有的素数的程序代码和运行截图 目录 前言 一、1-100之间所有的素数 1.1 运行流程及思想 1.2 代码段 1.3 JavaScript语句代码 1.4 运行截图 前言 1.若有选择,您可以在目录里进行快速查找; 2.本博文代码可以根据题目要求实现…

防火墙(二)

进一步了解防火墙 一、SNAT原理与应用模拟实验 二、DNAT的原理与应用模拟实验 三、抓包四、防火墙规则的备份和还原 一、SNAT原理与应用 SNAT应用环境:局域网主机共享单个公网IP地址接入Internet(私有不能早Internet中正常路由) SNAT原理&am…

【2023 · CANN训练营第一季】新手班 昇腾AI入门课(PyTorch)

1 昇腾AI全栈架构 昇腾计算产业是基于昇腾系列处理器和基础软件构睫的全栈Al计算基础设施.行业应用及服务,包括昇腾系列处理器、Atlas系列硬件、CANN (Compute Architecture for Neural Networks,异构计算架构》、Al计算框架、应用使能、全流…

nRF52832 定时器REPEATED模式,导致异常重启的问题排查全过程

文章目录 一、遇到问题二、JLink连接时,无法复现三、查看日志四、回退改动五、解决问题六、问题剖析 一、遇到问题 nRF52832项目增加一个功能,自测没问题就发出去了。结果300台机器,有7台出现异常,无法正常使用。细看了一遍提价上…

论文阅读_音频生成_AudioLM

论文信息 name_en: AudioLM: a Language Modeling Approach to Audio Generation name_ch: AudioLM:一种音频生成的语言建模方法 paper_addr: http://arxiv.org/abs/2209.03143 doi: https://doi.org/10.48550/arXiv.2209.03143 date_read: 2023-04-25 date_publis…

打开数据结构大门——实现小小顺序表

文章目录 前言顺序表的概念及分类搭建项目(Seqlist):apple:搭建一个顺序表结构&&定义所需头文件&&函数:banana:初始化:pear:打印:watermelon:数据个数:smile:检查容量:fireworks:判空:tea:在尾部插入数据:tomato:在尾部删除数据:lemon:在…

封装Appium启动参数,提高自动化测试效率的关键

目录 前言: 一、开发环境搭建 二、代码实现 1.导入Appium相关的库文件。 2.创建Appium的启动参数对象,并设置相关参数。 3.启动测试服务。 4.执行测试用例。 5.结束测试服务。 三、总结 前言: Appium是一款广泛使用的自动化测试工具…

Microsoft Office 2007的安装

哈喽,大家好。今天一起学习的是office2007的安装,有兴趣的小伙伴也可以来一起试试手。 一、测试演示参数 演示操作系统:Windows 7 不建议win10及以上操作系统使用 系统类型:64位 演示版本:cn_office_ultimate_2007_D…