设计模式之责任链模式

embedded/2024/9/22 23:28:55/

一、详细介绍

        责任链模式是一种行为型设计模式它允许将请求的发送者与接收者解耦,使多个对象都有机会处理请求,从而形成一条处理请求的责任链。当一个对象接收到请求时,它要么亲自处理请求,要么将请求转发给链上的下一个对象。请求在链上传递直至被处理或到达链尾。

责任链模式包含以下几个关键角色:

  1. 抽象处理者(Handler):定义处理请求的接口,通常包含一个指向下一个处理者的引用(nextHandler)和处理请求的方法(handleRequest)。

  2. 具体处理者(Concrete Handler):继承或实现抽象处理者,负责处理特定类型的请求。每个具体处理者决定是否处理请求,如果不处理,则将请求转发给下一个处理者。

二、使用场景

  1. 多个对象可能需要处理同一请求:当一个请求可能由多个对象处理时,可以使用责任链模式将这些对象链接起来,请求沿着链传递,直到被处理。

  2. 处理者需要动态指定:如果处理者的选择在运行时才能确定,可以使用责任链模式动态构建责任链,灵活调整请求的处理顺序。

  3. 请求处理需要分等级或优先级:责任链可以根据处理者的优先级或等级顺序进行构建,优先级高的处理者先处理请求。

三、注意事项

  1. 避免循环引用:构建责任链时要确保处理者之间的引用关系不会形成环状,否则会导致请求无法终止。

  2. 请求类型与处理者匹配:确保请求类型与处理者的处理能力相匹配,避免请求无法被正确处理。

  3. 处理结果的反馈:在某些情况下,可能需要处理结果返回至发起请求的对象,此时需考虑如何在责任链中传递处理结果。

四、优缺点

优点:

  1. 解耦发送者和接收者:请求的发送者无需知道请求将由哪个处理者最终处理,只需将请求发送到责任链的首部即可。

  2. 灵活性高:可以动态地添加、删除处理者,改变处理链的结构和请求的处理逻辑。

  3. 易于扩展:新增处理者类型时,只需实现抽象处理者接口,无需修改已有代码。

缺点:

  1. 请求可能未被处理:如果责任链没有正确配置,请求可能在链中传递到最后仍未被处理。

  2. 难以观察请求处理过程:由于请求在链中透明地传递,难以跟踪和调试请求的处理过程。

五、Java代码示例

以下是一个简单的Java代码示例,展示了使用责任链模式处理不同类型的消息请求:

java">// 抽象处理者(Handler)
abstract class MessageHandler {protected MessageHandler nextHandler;public void setNextHandler(MessageHandler handler) {this.nextHandler = handler;}public abstract void handleMessage(Message message);
}// 具体处理者(Concrete Handler)
class TextMessageHandler extends MessageHandler {@Overridepublic void handleMessage(Message message) {if (message instanceof TextMessage) {System.out.println("TextMessageHandler handled: " + message.getContent());} else if (nextHandler != null) {nextHandler.handleMessage(message);} else {System.out.println("No handler found for message type.");}}
}class ImageMessageHandler extends MessageHandler {@Overridepublic void handleMessage(Message message) {if (message instanceof ImageMessage) {System.out.println("ImageMessageHandler handled: " + message.getContent());} else if (nextHandler != null) {nextHandler.handleMessage(message);} else {System.out.println("No handler found for message type.");}}
}// 请求(Request)
class Message {private MessageType type;private String content;// 构造函数、getter、setter...public enum MessageType {TEXT, IMAGE}
}// 客户端代码
public class Client {public static void main(String[] args) {MessageHandler textHandler = new TextMessageHandler();MessageHandler imageHandler = new ImageMessageHandler();textHandler.setNextHandler(imageHandler);Message textMessage = new Message(MessageType.TEXT, "Hello, world!");textHandler.handleMessage(textMessage);Message imageMessage = new Message(MessageType.IMAGE, "image.jpg");textHandler.handleMessage(imageMessage);}
}

六、问题与解决方案

  1. 处理链过长导致性能下降:如果责任链过长,请求传递过程中可能会产生一定的性能开销。可以通过优化链的结构(如根据请求类型快速定位处理者)、使用并发处理等方法改善性能。

  2. 请求处理结果的传递:如果需要处理结果返回至发起请求的对象,可以在抽象处理者中添加一个handleResult()方法,并在具体处理者中实现该方法,将处理结果沿着链逆向传递。

七、与其他模式的对比

  1. 与观察者模式的对比:观察者模式中,多个对象订阅同一个事件源,当事件发生时,事件源通知所有订阅者。而在责任链模式中,请求沿着链传递,每个处理者有机会独立处理请求。

  2. 与策略模式的对比:策略模式根据上下文选择一个合适的策略(策略对象)来处理请求。责任链模式中,请求在多个处理者之间传递,每个处理者根据请求类型和自身能力决定是否处理。

  3. 与命令模式的对比:命令模式将请求封装为一个对象,可以进行排队、记录、撤销等操作。责任链模式关注的是请求的传递和处理,而非请求对象本身的操作。


http://www.ppmy.cn/embedded/23771.html

相关文章

【工具】--- Adobe Illustrator 下载-入门绘图

文章目录 软件下载入门项目可看课程 尝试使用Adobe Illustrator(设计师常用软件)进行科研绘图。 软件下载 阿里云盘下载 入门项目 绘制一个箭头并保持为SVG, 直线->画线->窗口->描边->选择想要的箭头样式->颜色->改为蓝…

【Flutter 面试题】 如何让 AppBar 的标题居中?

【Flutter 面试题】 如何让 AppBar 的标题居中? 文章目录 写在前面口述回答补充说明写在前面 🙋 关于我 ,小雨青年 👉 CSDN博客专家,GitChat专栏作者,阿里云社区专家博主,51CTO专家博主。2023博客之星TOP153。 👏🏻 正在学 Flutter 的同学,你好! 😊 Flutte…

react useEffect中removeEventListener没生效问题解决

在useEffect中写入window.removeEventListener没有生效,代码如下 useEffect(() > {const handleResize () > {console.log(window.innerWidth, window.innerHeight);};window.addEventListener(resize, handleResize);return () > {window.removeEventLi…

动态规划-子序列问题1

文章目录 1. 最长递增子序列(300)2. 摆动序列(376)3. 最长递增子序列的个数(673)4. 最长数对链(646) 1. 最长递增子序列(300) 题目描述: 状态表…

CSS接触

标签&#xff1a; 块标签&#xff0c;用来给网页分块 默认占一行<div></div> 无意义标签 <span></span> 背景颜色 background-color:颜色 字体颜色color: 颜色; 使用css&#xff1a; 一、使用css- 内嵌样式&#xff1a; 1. 在h…

stringRedisTemplate.opsForValue().increment(key)报空指针异常

解决办法&#xff1a;https://www.jianshu.com/p/789b33b5943e BUG复现满足以下条件可触发&#xff1a; 1.在RedisConfig开启Redis事务 redisTemplate.setEnableTransactionSupport(true);2.业务中开启事务 Transactional3.同一个业务下用生产多点id就报这个错误了 Cannot in…

Git变更账户、查看账户

1、变更账户 &#xff08;1&#xff09;修改当前文件夹用户 git config user.name “新用户名” git config user.email “新邮箱” &#xff08;2&#xff09;修改全局git用户 git config - -global user.name “新用户名” git config - -global user.email “新邮箱”…

银河麒麟V10 ARM64 离线安装 新版Docker

查询当前发行版本 nkvers下载最新版本 卸载旧依赖 卸载已经安装的老版本 yum remove docker \containerd.io \docker-runc \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine \docker-compo…