「聊设计模式」之职责链模式(Chain of Responsibility)

news2024/11/23 23:40:18

🏆本文收录于《聊设计模式》专栏,专门攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎持续关注&&收藏&&订阅!


前言

  设计模式是解决软件开发中常见问题的可复用解决方案。其中之一的职责链模式(Chain of Responsibility)是一种行为型模式,它允许多个对象都有机会处理请求,将请求沿着对象链传递,直到其中一个对象处理它为止。本文将详细介绍职责链模式的概念、实现及应用。

摘要

本文将分为以下几部分:

  1. 职责链模式概述
  2. 职责链模式的实现
  3. 职责链模式的应用场景
  4. 职责链模式与其他设计模式的比较
  5. 小结

职责链模式

概述

  职责链模式是一种行为型模式,它将请求的发送者和接收者解耦,将多个对象连成一条链,并将请求沿着链传递,直到有一个对象处理它为止。

  在职责链模式中,每个处理者都有机会处理请求,但是处理者并不知道下一个处理者是谁,请求会依次经过处理者链中的每个处理者,直到有一个处理者处理它为止。因此,职责链模式可以避免请求的发送者和接收者之间的耦合关系,以及将请求的处理从发送者中分离出来。

结构

职责链模式的结构主要包含以下几个角色:

  1. 抽象处理者(Handler):定义处理请求的接口,并维护一个指向下一个处理者的引用;

  2. 具体处理者(ConcreteHandler):实现处理请求的方法,如果不能处理则将请求转发给下一个处理者;

  3. 客户端(Client):创建处理者链,并将请求发送给链的第一个处理者;

其结构图如图 1 所示。客户端可按图 2 所示设置责任链。

图1 责任链模式结构图:
在这里插入图片描述

图2 责任链示意图:
在这里插入图片描述

职责链模式的应用场景

职责链模式适用于以下情况:

  1. 多个对象都有机会处理请求,但是不知道哪个对象最终会处理请求。
  2. 处理请求的对象集合可以动态配置,可以在运行时添加或删除处理对象。
  3. 发送者不需要知道请求的处理细节,只需要知道请求会被处理。

职责链模式常常应用于日志记录、异常处理、审批流程等场景。

职责链模式与其他设计模式的比较

职责链模式与其他设计模式的比较如下:

  1. 职责链模式、命令模式、解释器模式、中介者模式和观察者模式都涉及到处理请求或事件的对象间的交互。
  2. 职责链模式和命令模式都可以用于消除发送者与接收者之间的耦合关系,但是职责链模式强调的是处理链的传递,而命令模式强调的是将请求打包成命令。
  3. 职责链模式和解释器模式都可以用于解释语法规则,但是职责链模式强调的是处理链的传递,而解释器模式强调的是解释器的表达式。
  4. 职责链模式和中介者模式都可以用于减少对象间的耦合关系,但是职责链模式强调的是处理链的传递,而中介者模式强调的是中介者的协调作用。
  5. 职责链模式和观察者模式都可以用于处理事件,但是职责链模式强调的是处理链的传递,而观察者模式强调的是订阅者与发布者之间的通信。

职责链模式实现

职责链模式中涉及到三个角色:

  1. 抽象处理者(Handler):定义处理请求的接口,并保持一个指向下一个处理者的引用。
  2. 具体处理者(ConcreteHandler):实现抽象处理者接口,并负责处理请求。如果自己不能处理请求,会将请求转发给下一个处理者。
  3. 客户端(Client):创建处理者链,并向链头发送请求。

下面以Java语言为例,展示职责链模式的实现。

首先,定义抽象处理者接口Handler.java:

Handler

package com.example.javaDesignPattern.chainOfResponsibility;

/**
 * 抽象处理者接口
 *
 * @author bug菌
 * @version 1.0
 * @date 2023/9/19 17:29
 */
public abstract class Handler {
    protected Handler successor;

    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }

    public abstract void handleRequest(String request);
}

  其中,successor表示下一个处理者,setSuccessor()方法设置下一个处理者,handleRequest()方法声明处理请求的接口。

然后,定义具体处理者ConcreteHandler1.java:

ConcreteHandler1

package com.example.javaDesignPattern.chainOfResponsibility;

/**
 * @author bug菌
 * @version 1.0
 * @date 2023/9/19 17:29
 */
public class ConcreteHandler1 extends Handler {
    @Override
    public void handleRequest(String request) {
        if (request.equals("request1")) {
            System.out.println("ConcreteHandler1 handles request: " + request);
        } else {
            if (successor != null) {
                successor.handleRequest(request);
            }
        }
    }
}

  具体处理者实现了抽象处理者的接口,如果自己能够处理请求,就处理请求,否则将请求转发给下一个处理者。

定义另一个具体处理者ConcreteHandler2.java:

ConcreteHandler2

package com.example.javaDesignPattern.chainOfResponsibility;

/**
 * @author bug菌
 * @version 1.0
 * @date 2023/9/19 17:30
 */
public class ConcreteHandler2 extends Handler {
    @Override
    public void handleRequest(String request) {
        if (request.equals("request2")) {
            System.out.println("ConcreteHandler2 handles request: " + request);
        } else {
            if (successor != null) {
                successor.handleRequest(request);
            }
        }
    }
}

接下来,在客户端Client.java中创建处理者链,并向链头发送请求:

package com.example.javaDesignPattern.chainOfResponsibility;

/**
 * @author bug菌
 * @version 1.0
 * @date 2023/9/19 17:32
 */
public class Client {
    public static void main(String[] args) {
        Handler handler1 = new ConcreteHandler1();
        Handler handler2 = new ConcreteHandler2();
        handler1.setSuccessor(handler2);

        handler1.handleRequest("request1");
        handler1.handleRequest("request2");
    }
}

执行结果如下:

在这里插入图片描述
  当客户端向链头发送请求时,请求会沿着处理者链向下传递,直到有一个处理者处理它为止。

代码解读:

  如上示例展示了职责链模式(Chain of Responsibility Pattern)的使用。

  该模式包含多个处理器(Handler),每个处理器都处理一部分请求,但不是所有请求都能被处理。如果当前处理器不能处理请求,就将请求传递给下一个处理器,直到有处理器处理请求为止。该模式的使用可以实现请求的多级处理,让系统更加灵活。

  在这段代码中,Client类是职责链模式的客户端。它创建了两个具体处理器(ConcreteHandler1和ConcreteHandler2)并组织它们的处理顺序。在处理器1中设置处理器2为后继者(即其无法处理的请求由处理器2处理)。

  然后,Client类调用处理器1的handleRequest方法两次,分别传递"request1"和"request2"作为请求参数。在处理过程中,处理器1首先尝试处理请求1,由于它不能处理该请求,将其传递给后继者处理器2。处理器2成功地处理请求1,然后处理请求2。因为处理器1设置了处理器2为其后继者,请求2首先被处理器1处理,但由于处理器1仍然无法处理该请求,请求2最终由处理器2处理。

  因此,职责链模式能够有效地组织请求的处理顺序,增强系统的灵活性和可扩展性。

小结

  职责链模式是一种行为型模式,它允许多个对象都有机会处理请求,将请求沿着对象链传递,直到其中一个对象处理它为止。职责链模式可以避免请求的发送者和接收者之间的耦合关系,以及将请求的处理从发送者中分离出来。

  职责链模式由三个角色组成:抽象处理者、具体处理者和客户端。职责链模式适用于多个对象都有机会处理请求的场景。

  职责链模式与其他设计模式的比较表明,它与命令模式、解释器模式、中介者模式和观察者模式都有相似之处,但是强调的重点不同。

附录源码

  如上涉及代码均已上传同步在GitHub,提供给同学们参考性学习。

☀️建议/推荐你


  如果想系统性的全面学习设计模式,建议小伙伴们直接毫无顾忌的关注这个专栏《聊设计模式》,无论你是想提升自己的编程技术,还是渴望更好地理解代码背后的设计思想,本专栏都会为你提供实用的知识和启发,帮助你更好地解决日常开发中的挑战,将代码变得更加优雅、灵活和可维护!

📣关于我


我是bug菌,CSDN | 掘金 | infoQ | 51CTO 等社区博客专家,历届博客之星Top30,掘金年度人气作者Top40,51CTO年度博主Top12,华为云 | 阿里云| 腾讯云等社区优质创作者,全网粉丝合计15w+ ;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板等海量资料。

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

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

相关文章

一篇文章教你Pytest快速入门和基础讲解,一定要看!

前言 目前有两种纯测试的测试框架,pytest和unittestunittest应该是广为人知,而且也是老框架了,很多人都用来做自动化,无论是UI还是接口pytest是基于unittest开发的另一款更高级更好用的单元测试框架出去面试也好,跟别…

爬虫工作者必备:使用爬虫ip轻松获得最强辅助

在进行网络数据爬取时,爬虫ip成为了爬虫工作者们的得力辅助。通过使用爬虫ip,可以实现IP地址的伪装和分布式请求,有效规避访问限制和提高爬取效率。本文将为爬虫工作者们分享关于使用爬虫ip的知识,帮助您轻松获取最强辅助&#xf…

【JavaEE】多线程案例-单例模式

文章目录 1. 前言2. 什么是单例模式3. 如何实现单例模式3.1 饿汉模式3.2 懒汉模式4. 解决单例模式中遇到的线程安全问题4.1 加锁4.2 加上一个判断解决频繁加锁问题4.2 解决因指令重排序造成的线程不安全问题 1. 前言 单例模式是我们面试中最常考到的设计模式。什么是设计模式呢…

Linux 用户注意!GNOME 45 将影响所有扩展!

GNOME 45 是一次重要的升级,但对扩展的影响并不令人满意! 每当 GNOME 升级,总会有一些扩展遭遇问题,这点并不新鲜。但如今,到了 GNOME 45,每个扩展都将面临问题! 那么,究竟是什么原…

Lua学习笔记:探究package

前言 本篇在讲什么 理解Lua的package 本篇需要什么 对Lua语法有简单认知 对C语法有简单认知 依赖Visual Studio工具 本篇的特色 具有全流程的图文教学 重实践,轻理论,快速上手 提供全流程的源码内容 ★提高阅读体验★ 👉 ♠ 一级…

怒刷LeetCode的第8天(Java版)

目录 第一题 题目来源 题目内容 解决方法 方法一:双指针和排序 ​编辑第二题 题目来源 题目内容 解决方法 方法一:双指针 方法二:递归 方法三:快慢指针 方法四:栈 第三题 题目来源 题目内容 解决方法…

Python实现查询一个文件中的pdf文件中的关键字

要求,查询一个文件中的pdf文件中的关键字,输出关键字所在PDF文件的文件名及对应的页数。 import os import PyPDF2def search_pdf_files(folder_path, keywords):# 初始化结果字典,以关键字为键,值为包含关键字的页面和文件名列表…

数据分析三剑客之一:Pandas详解

目录 1 Pandas介绍 2 Pandas的安装与导入 2.1 Pandas模块安装 2.2 Pandas模块导入 3 pandas数据结构及函数 3.1 Series结构 3.1.1 ndarray创建Series对象 3.1.2 dict创建Series对象 3.1.3 标量创建Series对象 3.1.4 位置索引访问Series数据 3.1.5 标签索引访问Series…

华为云HECS安装docker

1、运行安装指令 yum install docker都选择y,直到安装成功 2、查看是否安装成功 运行版本查看指令,显示docker版本,证明安装成功 docker --version 或者 docker -v 3、启用并运行docker 3.1启用docker 指令 systemctl enable docker …

【Linux基础】第七章:搜索查找-find查找文件或者目录

find命令是根据文件属性进行查找的,如文件名,文件大小,所有者,所有组,是否为空,访问时间,修改时间等。 基本格式: find path [options] 先定位到etc 目录下 cd /etc1.按照文件名查找…

成集云 | 金蝶EAS集成聚水潭ERP(金蝶EAS主管库存)| 解决方案

源系统成集云目标系统 方案介绍 金蝶EAS是一款全球首款融合TOGAF标准SOA架构的企业管理软件,专门为大中型企业设计,以“创造无边界信息流”为产品设计理念,支持云计算、SOA和动态流程管理的整合技术平台。 聚水潭是一款以SaaS ER…

IP地址定位的基本原理

IP地址定位是一种用于确定互联网上设备地理位置的技术,它是网络管理、安全监控和市场定位等领域的重要工具。本文将深入探讨IP地址定位的基本原理,以及它是如何工作的。 1. IP地址的结构 IP地址是互联网上的设备的唯一标识符,它由一系列数字…

深入理解算法的时间复杂度

文章目录 时间复杂度的定义时间复杂度的分类时间复杂度分析常见数据结构和算法的时间复杂度常见数据结构常见算法 常见排序算法说明冒泡排序(Bubble Sort)快速排序(Quick Sort)归并排序(Merge Sort)堆排序(Heap Sort) 时间复杂度的定义 时间复杂度就是一种用来描述算法在输入规…

centos搭建activemq5.16

下载jdk、activemq(我这里都放在在/usr/local)之后。。。 在/usr/local/activemq/bin/目录下有一个env文件添加JAVA_HOME 注意activemq.xml里面不能出现中文,注释也不行 接下来在/usr/lib/systemd/system/创建activemq.service文件 # 单元节…

天选之子C++是如何发展起来的?如何学习C++呢?

天选之子C是如何发展起来的?如何学习C呢? 一、什么是C二、C发展史三、C的重要性3.1 语言的使用广泛度3.2 在工作领域 四、如何学习C4.1 大佬怎么学?4.2 自己怎么学 一、什么是C C语言是结构化和模块化的语言,适合处理较小规模的程序。对于复…

【LeetCode-中等题】107. 二叉树的层序遍历 II

文章目录 题目方法一:队列层序迭代 题目 方法一:队列层序迭代 解题详情:【LeetCode-中等题】102. 二叉树的层序遍历 res.add(0,zres); //效果是将 zres 列表作为 res 的第一个子列表,并将其它原本在第一位置及之后的子列表向后移…

1979-2021年地级市空气流通系数数据

1979-2021年地级市空气流通系数数据 1、时间:1979-2021年 2、来源:整理自era-interim 3、范围:367个地级市 4、指标:10米风速、边界层高度、空气流通系数 5、指标解释: 空气流动系数是空气污染的常用工具变量&am…

音视频转换器 Permute 3 for mac中文

Permute 3是一款界面简洁且易于使用的媒体文件格式转换器。它具有强大的转换功能,无需复杂的配置,只需将文件拖放到界面窗口,就能进行媒体转换,非常方便。 Permute 3支持视频、音乐和图像的格式转换,可以通过拖拽支持…

Jetpack Compose基础组件 - Image

Image的源码参数预览 Composable fun Image(painter: Painter,contentDescription: String?,modifier: Modifier Modifier,alignment: Alignment Alignment.Center,contentScale: ContentScale ContentScale.Fit,alpha: Float DefaultAlpha,colorFilter: ColorFilter? …