一文搞懂设计模式之责任链模式

大家好,我是晴天。我们又见面了,本周我们继续学习设计模式,本周将同大家一起学习责任链模式。

本文目录

场景引入

我们回想一下自己曾经经历过的考学场景,我们是如何一步一步考上大学的(为了简化过程只提取核心环节)。第一步,我们需要报名考试,第二步,我们需要去参加考试,第三步,我们才能够通过考试,顺利进入大学。这三个步骤必须要串行化执行,只有前一步通过了,我们才能进行后续的步骤,如果前一步没有通过,则提前终止整过流程,无需进行后续步骤了。
场景流程图

什么是责任链模式

责任链类图

责任链设计模式是一种行为型设计模式,它要求完成一件事情必须按照指定顺序进行,前一个环节完成了才能进行下一个环节,否则就提前终止。每个环节可以理解成一个链表的节点,当这个节点接收到上一个节点传送过来的信息时,开始进行自身的逻辑处理,处理完成后,传递给下一个节点,调用下一个节点的处理方法,直到链表遍历完成为止。

为什么需要责任链模式

责任链设计模式是一种行为型设计模式,它主要用于将请求沿着处理链传递,直到有一个处理者能够处理该请求为止。责任链模式有助于降低发送者和接收者之间的耦合度,使系统更加灵活和可扩展。

代码实战

实现顺序执行逻辑有两种处理方法,一种遍历方式,是将处理方法放到数组中,遍历处理方法即可,第二种就是使用责任链模式来处理。我们依次来看一下这两种实现方式。

遍历方式

package mainimport ("context""errors""fmt"
)type Student1 struct {Name     stringSignUp   bool // 是否考试报名TakeTest bool // 是否参加考试PassExam bool // 是否通过考试
}type handler1 func(ctx context.Context, stu *Student1) error// 报名考试
func SignUp1(ctx context.Context, stu *Student1) error {if stu.SignUp {fmt.Println(stu.Name + "已经报名了考试")return errors.New(stu.Name + "已经报名了考试了")}stu.SignUp = truefmt.Println(stu.Name + "正在进行考试报名")return nil
}// 参加考试
func TakeTest1(ctx context.Context, stu *Student1) error {if stu.TakeTest {fmt.Println(stu.Name + "已经参加了考试")return errors.New(stu.Name + "已经参加过考试了")}stu.TakeTest = truefmt.Println(stu.Name + "正在参加考试")return nil
}// 通过考试
func PassExam1(ctx context.Context, stu *Student1) error {if stu.PassExam {fmt.Println(stu.Name + "已经通过了考试")return errors.New(stu.Name + "已经通过了考试")}stu.PassExam = truefmt.Println(stu.Name + "通过了考试")return nil
}func main() {var handlers = []handler1{SignUp1, TakeTest1, PassExam1}var student = &Student1{Name: "张三",}for _, handler := range handlers {if err := handler(context.Background(), student); err != nil {fmt.Println(err)}}
}// 输出:
张三正在进行考试报名
张三正在参加考试
张三通过了考试

代码解释

上述代码定义了三个方法,分别是报名考试(SignUp1)、参加考试(TakeTest)和通过考试(PassExam),这三种方法按照顺序,组成处理方法数组,依次对Student1进行处理,如果某个方法已经判断状态为 true 了,则说明该环节已经参与过了,不需要再进行后续环节的处理了。

责任链模式

package mainimport "fmt"// 责任链模式
/*定义学生考学场景:step1:报名考试step2:参加考试step3:通过考试
*/// 学生
type Student struct {Name     stringSignUp   bool // 报名考试TakeTest bool // 参加考试PassExam bool // 通过考试
}type Section interface {Do(s *Student)           // 参与改环节setNext(section Section) // 设置下一个环节
}// 学生报名考试
type SignUp struct {next Section
}func (s *SignUp) Do(stu *Student) {if stu.SignUp {fmt.Println(stu.Name + "报名考试成功")s.next.Do(stu)return}stu.SignUp = truefmt.Println(stu.Name + "考生正在报名...")s.next.Do(stu)return
}func (s *SignUp) setNext(section Section) {s.next = section
}// 学生参加考试
type TakeTest struct {next Section
}func (p *TakeTest) Do(stu *Student) {if stu.TakeTest {fmt.Println(stu.Name + "参加考试")p.next.Do(stu)return}stu.TakeTest = truefmt.Println(stu.Name + "考生参加考试...")p.next.Do(stu)return
}func (p *TakeTest) setNext(section Section) {p.next = section
}// 学生通过考试
// 责任链最后一个节点,不需要请求后续节点的 Do 方法了
type PassExam struct {next Section
}func (p *PassExam) Do(stu *Student) {if stu.PassExam {fmt.Println(stu.Name + "通过考试成功")return}stu.PassExam = truefmt.Println(stu.Name + "通过考试...")return
}func (p *PassExam) setNext(section Section) {p.next = section
}func main() {var student = &Student{Name:     "张三",SignUp:   false,TakeTest: false,PassExam: false,}// 最后一个节点var pe = &PassExam{}// 倒数第二个节点var pt = &TakeTest{}// 倒数第三个节点var su = &SignUp{}// 把责任链的节点连接起来pt.setNext(pe)su.setNext(pt)// 调用责任链的首个节点的执行方法su.Do(student)
}

代码解释

上述代码实现了一个具有三个节点的责任链,三个节点分别是SignUp(报名考试)、TakeTest(参加考试)、PassExam(通过考试),每个责任链的节点都是一个 Section 类型,每个节点都实现了两个方法,一个是执行自身逻辑的 Do 方法,另一个就是连接下一个节点的 setNext 方法。这里注意,最后一个节点 PassExam 不需要调用下一个节点了(已经是最后一个节点了)。

两种处理方式的对比

遍历方式优点

  1. 遍历方式结构简单,能够方便地将处理方法按照指定顺序,对请求进行处理。

遍历方式缺点

  1. 每个处理方法之间没有必然的联系,无法通过上一个处理方法找到写一个处理方法,关联性不强。

责任链模式优点

  1. 节点之间相互串联,关联性比较强,当前节点可以根据自身节点的处理结果来决定是否将请求继续向下传递。
  2. 执行一整条责任链的逻辑处理,只需要调用头节点处理方法即可,就像是只调用了一个节点的处理方法一样。

总结

本文,我们介绍了什么是责任链模式,为什么需要责任链模式,遍历方式和责任链模式的使用方法,并且对比了遍历方式和责任链模式的优缺点。希望各位读者小伙伴能有些许收获。

写在最后

感谢大家的阅读,晴天将继续努力,分享更多有趣且实用的主题,如有错误和纰漏,欢迎留言给予指正。 更多文章敬请关注作者个人公众号 晴天码字。 我们下期不见不散,to be continued…

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

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

相关文章

如何使用vue组件

目录 1:组件之间的父子关系 2:使用组件的三个步骤 3:components组件的是私有子组件 4:在main.js文件中使用Vue.component全局注册组件 1:组件之间的父子关系 一:首先封装好的组件是不存在任何的关系的…

springboot(ssm家政服务系统 家政预约平台Java(codeLW)

springboot(ssm家政服务系统 家政预约平台Java(code&LW) 开发语言:Java 框架:ssm/springboot vue JDK版本:JDK1.8(或11) 服务器:tomcat 数据库:mysql 5.7(或8.0&#xff09…

强化学习简明教程

到目前为止,我们主要关注监督学习问题(主要是分类)。 在监督学习中,我们得到某种由输入/输出对组成的训练数据,目标是能够在学习模型后根据一些新输入来预测输出。 例如,我们之前研究过 MNIST 的卷积神经网…

阅读笔记|A Survey of Large Language Models

阅读笔记 模型选择:是否一定要选择参数量巨大的模型?如果需要更好的泛化能力,用于处理非单一的任务,例如对话,则可用选更大的模型;而对于单一明确的任务,则不一定越大越好,参数小一…

Python简单模拟蓝牙车钥匙协议

本文设计一个简单的蓝牙车钥匙协议,协议包含DH密钥协商和基于RSA的身份认证功能,以及防重放与消息完整性验证。 1. 密钥协商过程: - 设定 DH 参数:素数 p 和生成元 g。 - 发送方(Alice)生成 DH 的私钥 a 并计算公钥 A…

.sketch的文件转.psd文件

我们不能直接把sketch 转成 psd格式,但是还是有迂回办法的!一起跟随我来看看吧 第一步: 在即时设计官网首页「文件导入」的下拉菜单里,选择「Sketch 文件导入」,然后将需要转换的 Sketch 文件导入,接着直接…

web前端之vue3

MENU vue3响应式数据的判断、isRef、isReactive、isReadonly、isProxy、ref、reactive、readonlyvue3的生命周期vue3手写isRef、isReactive、isReadonly、isProxyvue3手写ref、深的refvue3手写shallowRef、浅的refvue3customRefvue3readonly与shallowReadonlyvue3toRaw与markRa…

BearPi Std 板从入门到放弃 - 1 引气入体篇

安装相关开发工具 Keil MDK 工具下载 略, 自行体会 Keil 芯片支持包下载 Keil 包 网址 https://www.keil.com/pack 此处下载的是STM32L4xx的支持包 https://www.keil.com/pack/Keil.STM32L4xx_DFP.2.6.2.pack STM32CubeMX 下载与包下载 i. 下载(需要使用用户&…

DouyinAPI接口系列丨Douyin商品详情数据接口丨Douyin视频详情数据接口

抖音商品详情API是抖音开放平台提供的一套API接口,用于获取商品详情信息。通过该API,开发者可以获取到商品的详细信息,包括商品ID、名称、描述、价格、销量、评价等信息。 在使用抖音商品详情API之前,需要先注册并登录抖音开放平…

fl studio21.2最新汉化中文完整版网盘下载

fl studio 21中文版是Image-Line公司继20版本之后更新的水果音乐制作软件,很多用户不太理解,为什么新版本不叫fl studio 21或fl studio2024,非得直接跳到21.2版本,其实该版本是为了纪念该公司22周年,所以该版本也是推出…

系统监控:使用日志文件 journalctl的使用

journalctl 显示最近登录的: 上面有最近登录的时间,和系统操作 几十年来,Linux日志记录一直由syslogd守护进程管理。Syslogd将收集系统处理和应用程序发送到/dev/log伪设备的日志消息。然后,它会将消息定向到/var/log/目录中适当…

MacDroid Pro for Mac – 安卓设备文件传输助手,实现无缝连接与传输!

想要在Mac电脑上轻松管理和传输您的安卓设备文件吗?MacDroid Pro for Mac 是您的最佳选择!这款强大的文件传输助手可以让您在Mac上与安卓设备之间实现快速、方便的文件传输。 MacDroid Pro for Mac 提供了简单易用的界面,让您能够直接在Mac上…

人工智能和网络安全:坏与好

人工智能似乎可以并且已经被用来帮助网络犯罪和网络攻击的各个方面。 人工智能可以用来令人信服地模仿真人的声音。人工智能工具可以帮助诈骗者制作更好、语法正确的网络钓鱼消息(而糟糕的语法往往会暴露出漏洞),并将其翻译成多种语言&…

字符函数 和 字符串函数

今天我打算介绍一些字符函数和字符串函数,有一些字符串函数我实现了模拟,但文章中没有放出来,如果需要的欢迎来到我的gitee里面拿取(在test.c11-23里面) 这是我的gitee:小汐 (lhysxx) - Gitee.com 字符函数 1. islow…

matlab操作方法(一)——向量及其操作

1.向量及其操作 matlab是英文Matrix Laboratory(矩阵实验室)的简称,是基于矩阵运算的操作环境。matlab中的所有数据都是以矩阵或多维数组的形式存储的。向量和标量是矩阵的两种特殊形式 向量是指单行或者单列的矩阵,它是构成矩阵…

C语言易错知识点八(结构体)

结构体 世间万物,上至飞禽,下至走兽,全都知道一件事:三个臭皮匠,顶个诸葛亮。(假的)即使是处于人类前沿的编程语言也知道要把数据联合在一起,于是便有了数组,结构体&…

org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource

DynamicDataSource-CSDN博客 /** Copyright 2002-2020 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the L…

鸿蒙工具DevEco Studio调试Build task failed. Open the Run window to view details.

DevEco Studio 预览代码时候出现的问题 1.进入设置 2.打开设置,构建,执行,部署下面的Hvigor, 把构建守护进程关掉就行。 然后重启启动一下就好了

破解app思路

1.会看smali代码逻辑 一.快速定位关键代码 1.分析流程 搜索特征字符串 搜索关键 api 通过方法名来判断方法的功能 2.快速定位关键代码 反编译 APK 程序 AndroidManifest.xml>包名/系统版本/组件 程序的主 activity(程序入口界面) 每个 Android 程序…

Redis SDS 源码

底层数据结构的好处: 杜绝缓冲区溢出。减少修改字符串长度时所需的内存重分配次数。二进制安全。兼容部分C字符串函数。 常用命令: set key value、get key 等 应用场景:共享 session、分布式锁,计数器、限流。 1、给char*定义…