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

2023年 9月 22日 20.1k 0

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

大家下午好,我是bug菌,今天我们继续聊设计模式。

前言

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

摘要

本文将分为以下几部分:

  • 职责链模式概述
  • 职责链模式的结构分析
  • 职责链模式的优缺点
  • 职责链模式的应用场景
  • 职责链模式与其他设计模式的比较
  • 模式实现
  • 小结
  • 职责链模式

    概述

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

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

    结构

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

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

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

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

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

    图1 责任链模式结构图:

    在这里插入图片描述

    图2 责任链示意图:

    在这里插入图片描述

    优缺点

    优点:

    职责链模式的优点如下:

  • 解耦:职责链模式将请求的发送者和接收者解耦,使得请求的发送者不需要知道请求的接收者是谁,也不需要知道请求是如何被处理的。

  • 灵活性:可以动态地重新组织职责链来满足需要。

  • 可扩展性:可以增加或修改处理请求的节点,增强了系统的灵活性。

  • 易于维护:每个节点只需要关注自己的处理逻辑,方便了对系统的维护。

  • 缺点:

    缺点:职责链模式的缺点如下:

  • 由于请求会经过多个节点处理,因此可能会影响系统的性能。

  • 职责链模式的节点数量需要根据业务场景来确定,如果节点过多或过少都不利于系统的运行。

  • 如果链条过长,可能会造成系统的复杂度增加。

  • 有可能会造成某个请求永远得不到处理,或者会重复被多个节点处理,需要控制好职责链的设计。

  • 应用场景

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

  • 多个对象都有机会处理请求,但是不知道哪个对象最终会处理请求。
  • 处理请求的对象集合可以动态配置,可以在运行时添加或删除处理对象。
  • 发送者不需要知道请求的处理细节,只需要知道请求会被处理。
  • 职责链模式常常应用于日志记录、异常处理、审批流程等场景。

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

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

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

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

  • 抽象处理者(Handler):定义处理请求的接口,并保持一个指向下一个处理者的引用。
  • 具体处理者(ConcreteHandler):实现抽象处理者接口,并负责处理请求。如果自己不能处理请求,会将请求转发给下一个处理者。
  • 客户端(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类是职责链模式的客户端。它创建了两个具体处理器(ConcreteHandler1ConcreteHandler2)并组织它们的处理顺序。在处理器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电子书籍、简历模板等海量资料。

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论