行为型设计模式——责任链模式

news/2024/5/19 12:55:40 标签: 设计模式, 责任链模式

摘要

责任链模式(Chain of responsibility pattern): 通过责任链模式, 你可以为某个请求创建一个对象链. 每个对象依序检查此请求并对其进行处理或者将它传给链中的下一个对象。

一、责任链模式意图

职责链模式(Chain Of Responsibility) 是一种行为设计模式, 允许你将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。 将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

二、责任链模式场景

  • 当程序需要使用不同方式处理不同种类请求, 而且请求类型和顺序预先未知时,可以使用责任链模式
  • 当必须按顺序执行多个处理者时, 可以使用该模式。
  • 如果所需处理者及其顺序必须在运行时进行改变, 可以使用责任链模式

三、责任链模式类图

  1. 处理者 (Handler) 声明了所有具体处理者的通用接口。 该接口通常仅包含单个方法用于请求处理, 但有时其还会包含一个设置链上下个处理者的方法。

  2. 基础处理者 (Base Handler) 是一个可选的类, 你可以将所有处理者共用的样本代码放置在其中。

    通常情况下, 该类中定义了一个保存对于下个处理者引用的成员变量。 客户端可通过将处理者传递给上个处理者的构造函数或设定方法来创建链。 该类还可以实现默认的处理行为: 确定下个处理者存在后再将请求传递给它。

  3. 具体处理者 (Concrete Handlers) 包含处理请求的实际代码。 每个处理者接收到请求后, 都必须决定是否进行处理, 以及是否沿着链传递请求。

    处理者通常是独立且不可变的, 需要通过构造函数一次性地获得所有必要地数据。

  4. 客户端 (Client) 可根据程序逻辑一次性或者动态地生成链。 值得注意的是, 请求可发送给链上的任意一个处理者, 而非必须是第一个处理者。

四、责任链模式实现

public abstract class Handler {
    protected Handler successor;

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

    protected abstract void handleRequest(Request request);
}
public class ConcreteHandler1 extends Handler {
    public ConcreteHandler1(Handler successor) {
        super(successor);
    }

    @Override
    protected void handleRequest(Request request) {
        if (request.getType() == RequestType.type1) {
            System.out.println(request.getName() + " is handle by ConcreteHandler1");
            return;
        }
        if (successor != null) {
            successor.handleRequest(request);
        }
    }
}
public class ConcreteHandler2 extends Handler{
    public ConcreteHandler2(Handler successor) {
        super(successor);
    }

    @Override
    protected void handleRequest(Request request) {
        if (request.getType() == RequestType.type2) {
            System.out.println(request.getName() + " is handle by ConcreteHandler2");
            return;
        }
        if (successor != null) {
            successor.handleRequest(request);
        }
    }
}
public class Request {
    private RequestType type;
    private String name;

    public Request(RequestType type, String name) {
        this.type = type;
        this.name = name;
    }

    public RequestType getType() {
        return type;
    }

    public String getName() {
        return name;
    }
}
public enum RequestType {
    type1, type2
}
public class Client {
    public static void main(String[] args) {
        Handler handler1 = new ConcreteHandler1(null);
        Handler handler2 = new ConcreteHandler2(handler1);
        Request request1 = new Request(RequestType.type1, "request1");
        handler2.handleRequest(request1);
        Request request2 = new Request(RequestType.type2, "request2");
        handler2.handleRequest(request2);
    }
}

五、责任链模式总结

责任链模式、命令模式、中介者模式和观察者模式都是用于处理请求发送者和接收者之间的不同连接方式:

  • 责任链按照顺序将请求动态传递给一系列的潜在接收者, 直至其中一名接收者对请求进行处理。
  • 命令在发送者和请求者之间建立单向连接。
  • 中介者清除了发送者和请求者之间的直接连接, 强制它们通过一个中介对象进行间接沟通。
  • 观察者允许接收者动态地订阅或取消接收请求。

责任链模式通常与组合模式结合使用。 在这种情况下, 叶子组件接收到请求后, 可以将请求沿包含全体父组件的链一直传递至对象树的底部。

责任链模式使用命令模式实现,在这种情况下, 你可以对由请求代表的同一个上下文对象执行许多不同的操作。还有另外一种实现方式, 那就是请求自身就是一个命令对象。 在这种情况下, 你可以对由一系列不同上下文连接而成的链执行相同的操作。

责任链与装饰器模式类结构非常相似。 两者都依赖递归组合将需要执行的操作传递给一系列对象。 但是, 两者有几点重要的不同之处。责任链管理者可以相互独立地执行一切操作, 还可以随时停止传递请求。 另一方面, 各种装饰可以在遵循基本接口的情况下扩展对象的行为。 此外, 装饰无法中断请求的传递。

六、责任链模式开源示例

使用示例: 责任链模式在 Java 程序中并不常见, 因为它仅在代码与对象链打交道时才能发挥作用。该模式最流行的使用案例之一是在 GUI 类中将事件向上传递给父组件。 另一个值得注意的使用案例是依次访问过滤器。

下面是该模式在核心 Java 程序库中的一些示例:

  • javax.servlet.Filter#doFilter()(opens new window)
  • java.util.logging.Logger#log()(opens new window)

识别方法: 该模式可通过一组对象的行为方法间接调用其他对象的相同方法来识别, 而且所有对象都会遵循相同的接口。

博文参考

行为型 - 责任链(Chain Of Responsibility) | Java 全栈知识体系

设计模式之职责链模式 | DESIGN


http://www.niftyadmin.cn/n/5057574.html

相关文章

学习编写代码的挑战与经验

学习编写代码的挑战与经验 引言 刚开始学习编写代码的时候,每个人都会遇到各种各样的挑战。有时候我们写出的代码可能会让自己觉得愚蠢,但这其实是一个很正常的过程。在这篇文章中,我想分享一些我在学习编写代码时遇到的挑战以及我从中学到的…

python爬虫:JavaScript 混淆、逆向技术

Python爬虫在面对JavaScript混淆和逆向技术时可能会遇到一些挑战,因为JavaScript混淆技术和逆向技术可以有效地阻止爬虫对网站内容的正常抓取。以下是一些应对这些挑战的方法: 分析网页源代码:首先,尝试分析网页的源代码&#xf…

Android Shape设置背景

设置背景时&#xff0c;经常这样 android:background“drawable/xxx” 。如果是纯色图片&#xff0c;可以考虑用 shape 替代。 shape 相比图片&#xff0c;减少资源占用&#xff0c;缩减APK体积。 开始使用。 <?xml version"1.0" encoding"utf-8"?…

在vue使用wangEditor(简单使用)

wangEditor不同的版本使用方法都不一样&#xff0c;这里以目前最新的参考官网方法使用2023-09-28 首先安装&#xff0c;参考官网&#xff0c;注意editor跟editor-for-vue两个都要装 yarn add wangeditor/editor # 或者 npm install wangeditor/editor --saveyarn add wangedit…

PHP 创建 MySQL 表

目录 PHP 创建 MySQL 表 使用 MySQLi 和 PDO 创建 MySQL 表 实例 (MySQLi - 面向对象) 实例 (MySQLi - 面向过程) 实例 (PDO) PHP 创建 MySQL 表 一个数据表有一个唯一名称&#xff0c;并有行和列组成。 使用 MySQLi 和 PDO 创建 MySQL 表 CREATE TABLE 语句用于创建 MySQ…

Ubuntu系统Linux内核安装和使用

安装&#xff1a; 检查树莓派Linux版本&#xff0c;我的是6.1 uname -r 内核下载链接&#xff1a; Raspberry Pi GitHub 找对应版本下载 导入之后&#xff0c;解压安装即可 unzip linux-rpi-6.1.y.zip 其他内容 treee 指令安装 sudo apt-get install tree 使用这…

openstack的组成

OpenStack 是一个开源的云计算平台&#xff0c;由一系列组件构成&#xff0c;各组件之间相互协作&#xff0c;提供了完整的基础设施即服务&#xff08;IaaS&#xff09;解决方案。下面详细解释了 OpenStack 的主要组件及其相互关系&#xff1a; Nova&#xff08;计算服务&…

centos脚本获取昨天日期删除指定文件之外的其他文件

一、centos脚本获取昨天日期 昨天 dname1"$(date -d -1day %Y%m%d)" 前天 dname1"$(date -d -2day %Y%m%d)" 大前天 dname2"$(date -d -3day %Y%m%d)" 明天 dname1"$(date -d 1day %Y%m%d)" 后天 dname1"$(date -d 2day %Y%…