JS设计模式之职责链模式:优雅地处理请求流程

image.png

一. 前言

在前端开发中,我们经常会遇到需要按照一定的顺序处理一系列请求或操作的情况,如果将每一步处理都硬编码在一起,会导致代码臃肿,可维护性和可扩展性都会大大降低。而职责链模式恰好提供了一种优雅的解决方案。

无论你是希望优化代码结构、加强代码的灵活性,还是提高代码的可维护性和可扩展性,职责链模式都是一个非常有价值的设计模式。

接下来,跟随我一起探索 JavaScript 中的职责链模式!

二. 什么是职责链模式

1. 基础概念

职责链模式(Chain of Responsibility Pattern)是一种行为设计模式,它允许多个对象(处理者)依次处理同一个请求,直到其中的一个处理者能够处理该请求为止。在职责链模式中,请求沿着链条依次传递,每个处理者决定自己是否处理请求,如果处理者无法处理请求,则将请求传递给链条上的下一个处理者。

在 JavaScript 中,职责链模式通常由一系列对象(处理者)组成,它们共同形成一个处理请求的链条。每个处理者都包含一个处理请求的方法,并且拥有一个指向下一个处理者的引用。当一个请求被发起时,它将从链条的开头开始传递,直至有一个处理者能够完全处理请求为止。

职责链模式包括以下几个核心概念:

  1. 处理者(Handler):处理者是职责链模式中的关键角色,每个处理者都定义了处理请求的方法,并持有一个指向下一个处理者的引用。处理者通常包含一个处理请求的方法(例如handleRequest),在该方法中处理请求或者将请求传递给下一个处理者。

  2. 链条(Chain):处理者构成了一个链条,请求沿着链条从一个处理者传递到另一个处理者。链条的组织和顺序决定了请求的处理顺序。

  3. 请求(Request):请求是需要被处理的对象或信息。请求经过链条中的每个处理者,直到有一个处理者能够完全处理请求。

  4. 传递请求(Passing the Request):处理者在处理请求时,可以选择自己处理请求,也可以将请求传递给下一个处理者。这样,请求可以着链条传递并得到处理。

通过职责链模式,我们可以将请求的发送者和接收者解耦,灵活地构建处理请求的流程。这样可以增强代码的灵活性和可维护性,同时使得系统更易于扩展和修改。

2. UML 图

根据上面的几个核心概念,我们可以对职责链模式使用以下 UML 类图来描述:

image.png

在上面的类图中:

  • Handler 是抽象处理者,定义了一个处理请求的接口和一个指向下一个处理者的引用(successor)。

  • ConcreteHandlerAConcreteHandlerB 是具体处理者,实现了 Handler 中定义的处理请求的方法 handleRequest,并根据自身责任来处理请求。如果自己无法处理,就将请求传递给下一个处理者。

在职责链模式中,请求从发起经过一条链条上的处理者依次处理,直到找到合适的处理者为止。每个处理者都只关注自己的处理逻辑,可以灵活地添加、修改或删除处理者,使系统更加灵活和可扩展。

3. 作用

JavaScript 职责链模式的作用主要包括以下几个方面:

  1. 解耦责任处理者:将发送者和接收者解耦,使发送者无需知道具体的接收者是谁,以及如何处理请求。每个处理者只需关注自己的责任范围,大大降低了处理者之间的耦合度。

  2. 动态处理请求:职责链模式的链条结构可以动态地调整和修改,可以随时添加新的处理者或者移除现有的处理者,以适应不同的需求。

  3. 灵活性:每个处理者只需关注自己的责任,可以根据请求的不同部分进行不同的处理,使得系统更容易进行扩展和维护。

  4. 降低耦合度:将不同的处理逻辑分离开来,使得每个处理者只需关注自己的责任范围,降低模块之间的耦合度,提高系统的可维护性和可扩展性。

职责链模式的作用在于提供了一种灵活、可扩展的方式来处理复杂的请求处理流程,降低模块之间的耦合度,使得系统更容易维护和扩展。

三. 实现方式

在 JavaScript 中,实现职责链模式通常需要以下几个步骤:

  1. 定义处理者对象,处理者对象需要包含处理请求的方法,并且持有对下一个处理者的引用。

  2. 创建一个链条,将处理者按照一定的顺序连接起来。

  3. 发送请求,并且沿着链条传递请求,直到找到能够完全处理请求的处理者为止。

简单示例代码:

// 定义处理者对象
class Handler {constructor(name) {this.name = name;this.nextHandler = null;}setNextHandler(handler) {this.nextHandler = handler;}handleRequest(request) {if (this.canHandleRequest(request)) {console.log(`${this.name} 处理了请求:${request}`);} else if (this.nextHandler) {console.log(`${this.name} 不能处理请求,传递给下一个处理者`);this.nextHandler.handleRequest(request);} else {console.log("没有处理者可以处理该请求");}}canHandleRequest(request) {return false;}
}// 创建具体的处理者对象
class ConcreteHandler1 extends Handler {canHandleRequest(request) {return request === "A";}
}class ConcreteHandler2 extends Handler {canHandleRequest(request) {return request === "B";}
}class ConcreteHandler3 extends Handler {canHandleRequest(request) {return request === "C";}
}// 创建处理者链条
const handler1 = new ConcreteHandler1("Handler 1");
const handler2 = new ConcreteHandler2("Handler 2");
const handler3 = new ConcreteHandler3("Handler 3");handler1.setNextHandler(handler2);
handler2.setNextHandler(handler3);// 发送请求
handler1.handleRequest("A");
handler1.handleRequest("B");
handler1.handleRequest("C");
handler1.handleRequest("D");

执行结果如下图所示:

image.png

在上面的示例中,我们首先定义了一个抽象的处理者类Handler,具体的处理者对象ConcreteHandler1ConcreteHandler2ConcreteHandler3继承自抽象处理者类,并实现了具体的请求处理逻辑。然后创建了一个处理者链条,指定了处理者之间的顺序,并最后发送了多种不同的请求,观察处理者是如何根据自己的能力来处理请求或者将请求传递给下一个处理者的。

四. 应用场景

在 JavaScript 中,我总结了职责链模式适用的以下几种场景:

  1. 表单验证:在前端开发中,表单验证是一个常见的需求。可以使用职责链模式来实现多个验证规则的处理流程,每个验证规则作为一个处理者,根据规则是否匹配来决定是否处理表单验证请求。

  2. 请求处理:在网络请求处理中,可能需要经过多个处理步骤,每个处理步骤都有自己的处理逻辑,这时可以使用职责链模式来实现请求处理流程。

  3. 权限校验:在权限校验中,可能存在不同级别的权限验证逻辑,使用职责链模式可以实现逐级权限验证,直到找到对应权限处理者为止。

除此之外,可以在其他方面也有类似的使用该模式应用的场景,例如:事件处理、异常处理等等,类似的还有很多。但总体来说,职责链模式适用于处理流程含有多个处理步骤,并且这些处理步骤可以灵活组合和扩展的场景。

下面我以表单验证为例,使用职责链模式来逐步验证表单输入是否符合要求。

// 定义处理者对象
class Validator {constructor(name, validatorFn) {this.name = name;this.validatorFn = validatorFn;this.nextValidator = null;}setNextValidator(validator) {this.nextValidator = validator;}validate(value) {if (this.validatorFn(value)) {if (this.nextValidator) {return this.nextValidator.validate(value);} else {return true;}} else {return false;}}
}// 具体的验证函数
const isNotEmpty = (value) => {return value.trim() !== "";
};const isEmail = (value) => {const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;return emailPattern.test(value);
};const isNumber = (value) => {return !isNaN(value) && isFinite(value);
};// 创建验证链条
const validator1 = new Validator("NotEmpty", isNotEmpty);
const validator2 = new Validator("IsEmail", isEmail);
const validator3 = new Validator("IsNumber", isNumber);validator1.setNextValidator(validator2);
validator2.setNextValidator(validator3);// 模拟表单数据
const formData = {email: "example@example.com",age: "25",address: "",
};// 进行表单验证
for (let key in formData) {const isValid = validator1.validate(formData[key]);console.log(`${key} validation: ${isValid}`);
}

在上述代码中,首先定义了三个具体的验证函数isNotEmptyisEmailisNumber,分别用于验证字段是否为空、是否为邮箱格式和是否为数字。然后创建了三个验证器对象,分别对应这三种验证函数,并且按照验证顺序连接起来形成了一个验证链条。最后,模拟了一个表单数据对象formData,对每个字段进行逐个验证,并输出验证结果。

image.png

这样,使用职责链模式来实现表单验证,可以在每个验证器中专注于自己的验证逻辑,保持代码的清晰度,同时也能方便地对验证规则进行扩展和定制。

五. 优缺点

通过以上的了解,总结一下在 JavaScript 中使用职责链模式的一些优点和缺点:

优点:

  1. 解耦责任:职责链模式将请求的发送者和接收者解耦,每个处理者只需关注自己的具体责任,使得系统更灵活、更易于扩展和维护。

  2. 简化对象:相比于将所有的处理逻辑集中在一个对象中,职责链模式将每个处理逻辑封装成一个独立的对象,避免了单个对象过于臃肿和复杂。

  3. 灵活性:可以根据需要动态地调整处理链条,可以随时添加、修改、删除处理者,灵活应对各种变化的需求。

  4. 封装性:每个处理者都只关心自己的处理逻辑,对其他处理者内部逻辑无需了解,增强了各处理者之间的独立性。

缺点:

  1. 性能损耗:因为需要遍历整个链条来寻找正确的处理者,所以在链条较长的情况下可能会导致性能损耗,特别是在处理大量数据时。

  2. 链条滞留:如果链条设计不合理或者处理者设置不当,可能导致请求在链条中滞留无法得到正确处理,影响系统的性能和稳定性。

  3. 调试困难:由于请求在链条中传递,可能需要跟踪整个链条才能定位问题,增加了调试的难度。

  4. 过度使用:如果你在追求过度使用职责链模式,可能会使系统变得复杂而难以理解。

因此,职责链模式在适当的场景下能够有效地简化代码结构、提高系统灵活性,但也需要谨慎使用,避免出现性能问题和复杂度提高。

六. 结语

在 JavaScript 中,职责链模式是一种非常有用的设计模式,它可以帮助我们更好地组织代码、简化逻辑、提高系统的灵活性和可扩展性。通过在不同处理者之间建立连接,并在需要时动态地调整处理链条,我们可以更好地应对复杂的业务逻辑和需求变化。

在编写和应用职责链模式时,我们需要注意合理地设计链条结构,避免性能损耗和链条滞留等问题。同时,也要注意避免过度使用职责链模式,保持代码的简洁和可维护性。

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

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

相关文章

大模型面试八股+答案,LLM-offer手到擒来!

你是否也曾为面试大模型八股文而苦恼?别担心!今天我就来给你分享一些绝妙的面试技巧,让你轻松应对! 🔍 第一关:了解题目 首先,一定要仔细阅读题目,理解清楚每个要求。明确问题的关键…

字母数字图像分割系统源码&数据集分享

字母数字图像分割系统源码&数据集分享 [yolov8-seg-C2f-Faster-EMA&yolov8-seg-C2f-DiverseBranchBlock等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challenge 项目…

硬件-PCB-叠层设计(四层板六层板)

文章目录 一:简介二:多层电路板结构三 PCB叠层设计的内容3.1 叠层设计的基本原则3.2 叠层设计的准备工作 四 六层PCB叠层方案介绍4.1 介绍常见的六层叠层结构并分析其优缺点 五 方案选择5.1 方案一:S-G-S-S-P-S5.2 方案二:S-S-G-P…

夹耳式耳机值得购买吗?这一篇文章扫清耳夹式耳机盲点!

近年来,夹耳式耳机备受很多人喜爱。主要原因在于这种耳机不入耳,既能保护我们的听力健康,又能让我们享受到极致的音乐体验。久而久之,人们反而对入耳式耳机戴着感到不习惯了。然而,一些想要入手夹耳式耳机的小伙伴却犯…

老板员工必看:钉钉聊天记录可以被监控吗?答案你万万想不到!

如今,无论是办公室还是居家远程工作,钉钉已经成为了许多公司不可或缺的沟通工具。 老板们依靠它安排工作、传递任务,员工们用它互相协作、讨论项目。可是,你有没有想过,钉钉聊天记录可以被监控吗? 答案可…

BP实战minist数据集

目录 前言 一、MNIST数据集介绍和加载 1.MNIST数据集介绍 2.加载数据集MNIST数据集 二、构建 BP 网络模型 1.神经网络结构图示 2.BP 网络模型代码解释 三、定义和训练BP 网络模型 四、训练结果 总结 前言 在当今人工智能与机器学习飞速发展的时代,神经网络…

SPI主从通讯稳定性之解决方法

在使用SPI通讯时,将硬件SPI用作主机的比较多,程序设计也比较容易,但是,若将硬件SPI用作从机了,网上的案例就比较少了,因为大家都有一个习惯,实在实现不了,就用软件模拟SPI来完成通讯…

函数式接口在Java中的应用与实践

1. 引言 函数式接口是Java 8引入的一个概念,它是指只有一个抽象方法的接口。函数式接口可以被用作lambda表达式的目标类型。在函数式接口中,除了抽象方法外,还可以有默认方法和静态方法。 函数式接口的引入是为了支持函数式编程&#xff0c…

Java项目: 基于SpringBoot+mybatis+maven+vue网上摄影工作室(含源码+数据库+任务书+毕业论文)

一、项目简介 本项目是一套基于SpringBootmybatismavenmavenvue网上摄影工作室 包含:项目源码、数据库脚本等,该项目附带全部源码可作为毕设使用。 项目都经过严格调试,eclipse或者idea 确保可以运行! 该系统功能完善、界面美观、…

【算法】博弈论(C/C++)

个人主页:摆烂小白敲代码 创作领域:算法、C/C 持续更新算法领域的文章,让博主在您的算法之路上祝您一臂之力 欢迎各位大佬莅临我的博客,您的关注、点赞、收藏、评论是我持续创作最大的动力 目录 博弈论: 1. Grundy数…

【MySQL】-- 表的操作

文章目录 1. 查看所有表1.1 语法 2. 创建表2.1 语法2.2 示例2.3 表在磁盘上对应的文件 3. 查看表结构3.1 语法3.2 示例 4. 查看创建表的语句5. 修改表5.1 语法5.2 示例5.2.1 向表中添加一列5.2.2 修改某列的长度5.2.3 重命名某列5.2.4 删除某个字段5.2.5 修改表名 6. 删除表6.1…

不入耳开放式耳机哪个品牌好?开放式耳机排行榜10强推荐!

不入耳开放式耳机哪个品牌好?开放式耳机排行榜10强推荐! 随着开放式耳机的日益流行,市场上的选择愈发多样,这有时会让消费者在挑选时感到迷茫,不知道哪个牌子的开放式耳机最好。为解决这一困扰,我精心筛选…

社区圈子系统 圈子社区系统 兴趣社区圈子论坛系统 圈子系统源码圈子系统的适用领域有哪些?如何打造自己的圈子圈子系统有哪些常见问题

社区圈子系统 圈子社区系统 兴趣社区圈子论坛系统 圈子系统源码圈子系统的适用领域有哪些?如何打造自己的圈子圈子系统有哪些常见问题 圈子系统的适用领域 圈子系统的适用领域广泛,涵盖了多个行业和场景,包括但不限于以下几个方面&#xff1…

Label Studio 半自动化标注

引言 Label Studio ML 后端是一个 SDK,用于包装您的机器学习代码并将其转换为 Web 服务器。Web 服务器可以连接到正在运行的 Label Studio 实例,以自动执行标记任务。我们提供了一个示例模型库,您可以在自己的工作流程中使用这些模型,也可以根据需要进行扩展和自定义。 1…

springboot邮件群发功能的开发与优化策略?

springboot邮件配置指南?如何实现spring邮件功能? SpringBoot框架因其简洁、高效的特点,成为了开发邮件群发功能的理想选择。AokSend将深入探讨SpringBoot邮件群发功能的开发过程,并提出一系列优化策略,以确保邮件发送…

常见的图像处理算法:均值滤波----mean filter

一、什么是均值滤波 均值滤波器是一种常见的图像滤波器,是典型的线性滤波算法。其基本原理是用一个给定的窗口覆盖图像中的每一个像素点,将窗口内的像素值求平均值,然后用这个平均值代替原来的像素值。均值滤波器可以去除噪声、平滑图像、减少…

代码随想录算法训练营Day28 | 39. 组合总和、40.组合总和Ⅱ、131.分割回文串

目录 39. 组合总和 40.组合总和Ⅱ 131.分割回文串 39. 组合总和 题目 39. 组合总和 - 力扣(LeetCode) 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不…

路径规划关于地图的整理

路径规划离不开地图,其中真实地图,栅格地图和RVIZ之间Grid显示之间很混乱,还有各个原点位置显示,不弄清发现map在rviz里显示老是偏的,专门学习记录一下。 RVIZ里Grid的全局坐标系原点,在默认在栅格中间&am…

软考学习笔记

学习资料: 数据库关系模式的范式总结_关系模式范式-CSDN博客 【范式】五大范式所解决的问题及说明_天空_新浪博客 (sina.com.cn) 求函数依赖: 根据函数依赖求候选码_证明存在部分依赖属于候选码-CSDN博客 关系范式: 1NF:若关…

xss-labs靶场第二关测试报告

目录 一、测试环境 1、系统环境 2、使用工具/软件 二、测试目的 三、操作过程 1、注入点寻找 2、使用hackbar进行payload测试 3、绕过结果 四、源代码分析 五、结论 一、测试环境 1、系统环境 渗透机:本机(127.0.0.1) 靶 机:本机(127.0.0.…