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

目录

什么是责任链模式

责任链模式的实现

责任链模式角色

责任链模式类图

责任链模式举例

责任链模式代码实现

责任链模式的特点

优点

缺点

使用场景

注意事项

实际应用


什么是责任链模式

        责任链模式(Chain of Responsibility Pattern)又叫职责链模式是一种行为型设计模式,它通过建立一个对象链来依次处理请求,将请求的发送者和接收者解耦,并允许多个对象都有机会处理请求。其目的是为了解决请求端与实现端的解耦。其实现过程类似递归调用。责任链模式的核心是定义责任链节点的接口以及节点之间的关系,它允许动态的增加和修改责任链中的节点。

责任链模式的实现

责任链模式角色

  1. 抽象处理者(Handler):定义了处理请求的接口,并维护一个指向下一处理者的引用。通常包含一个处理方法 handleRequest()。
  2. 具体处理者(ConcreteHandler):实现了抽象处理者接口,对请求进行具体处理,如果自身无法处理,则将请求转发给下一处理者。

责任链模式类图

责任链模式举例

        以公司采购审批为例,不同金额的采购需要不同人员的审批,比如20000以下需要项目经理审批,20000-50000需要部门经理审批,50000以上需要总经理审批。此时我们把审批流程可以看作一个审批责任链条,进而可以使用责任链模式。

责任链模式代码实现

实体请求类

package com.common.demo.pattern.chain;

import java.math.BigDecimal;

/**
 * @author Evan Walker 昂焱数据: https://www.ayshuju.com
 * @version 1.0
 * @desc 实体请求类
 * @date 2023/07/27 13:35:41
 */
public class PurchaseReq {

    /**
     * 请求类型
     */
    private int type;

    /**
     * 金额
     */
    private BigDecimal price;

    /**
     * 用途
     */
    private String purpose;

    public PurchaseReq(int type, BigDecimal price, String purpose) {
        this.type = type;
        this.price = price;
        this.purpose = purpose;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }

    public String getPurpose() {
        return purpose;
    }

    public void setPurpose(String purpose) {
        this.purpose = purpose;
    }

    @Override
    public String toString() {
        return "PurchaseReq{" +
                "type=" + type +
                ", price=" + price +
                ", purpose=" + purpose +
                '}';
    }
}

抽象处理者角色

package com.common.demo.pattern.chain;

/**
 * @author Evan Walker 昂焱数据: https://www.ayshuju.com
 * @version 1.0
 * @desc 抽象审批者处理类, 抽象处理者角色
 * @date 2023/07/27 13:44:42
 */
public abstract class Approver {

    Approver approver;
    String name;

    public Approver() {
    }

    public Approver(String name) {
        this.name = name;
    }

    /**
     * 下一个处理者
     */
    public void setApprover(Approver approver) {
        this.approver = approver;
    }



    /**
     * 处理审批请求的方法,得到一个请求,处理是子类实现
     */
    public abstract void process(PurchaseReq purchaseReq);

}

具体处理者角色

package com.common.demo.pattern.chain;

import java.math.BigDecimal;

/**
 * @author Evan Walker 昂焱数据: https://www.ayshuju.com
 * @version 1.0
 * @desc 项目经理 具体审批者
 * @date 2023/07/27 13:49:16
 */
public class ProjectManager extends Approver {

    public ProjectManager(String name) {
        super(name);
    }

    @Override
    public void process(PurchaseReq purchaseReq) {
        // 小于 5000 项目经理审批即可
        if (purchaseReq.getPrice().compareTo(new BigDecimal(5000)) == -1) {
            System.out.println("采购计划:"+purchaseReq.getPurpose()+",被"+this.name+"处理,审批终结!");
        } else {
            System.out.println("采购计划:"+purchaseReq.getPurpose()+",被"+this.name+"处理,进入下一级审批!");
            approver.process(purchaseReq);
        }
    }
}
package com.common.demo.pattern.chain;

import java.math.BigDecimal;

/**
 * @author Evan Walker 昂焱数据: https://www.ayshuju.com
 * @version 1.0
 * @desc 部门经理 具体审批者
 * @date 2023/07/27 13:49:48
 */
public class DepartmentManager extends Approver{

    public DepartmentManager(String name) {
        super(name);
    }

    @Override
    public void process(PurchaseReq purchaseReq) {
        // 小于 20000 大于 5000, 部门经理审批即可
        if(purchaseReq.getPrice().compareTo(new BigDecimal(20000))==-1){
            System.out.println("采购计划:"+purchaseReq.getPurpose()+",被"+this.name+"处理,审批终结!");
        } else {
            System.out.println("采购计划:"+purchaseReq.getPurpose()+",被"+this.name+"处理,进入下一级审批!");
            approver.process(purchaseReq);
        }
    }
}
package com.common.demo.pattern.chain;

import java.math.BigDecimal;

/**
 * @author Evan Walker 昂焱数据: https://www.ayshuju.com
 * @version 1.0
 * @desc 总经理 具体审批者
 * @date 2023/07/27 13:50:45
 */
public class GeneralManager extends Approver {

    public GeneralManager(String name) {
        super(name);
    }

    @Override
    public void process(PurchaseReq purchaseReq) {
        // 大于 20000 ,总经理审批
        if (new BigDecimal(20000).compareTo(purchaseReq.getPrice()) == -1) {
            System.out.println("采购计划:"+purchaseReq.getPurpose()+",被"+this.name+"处理,审批终结!");
        } else {
            System.out.println("采购计划:"+purchaseReq.getPurpose()+",被"+this.name+"处理,进入下一级审批!");
            approver.process(purchaseReq);
        }
    }
}

测试类

package com.common.demo.pattern.chain;

import java.math.BigDecimal;

/**
 * @author Evan Walker 昂焱数据: https://www.ayshuju.com
 * @version 1.0
 * @desc 测试类
 * @date 2023/07/27 14:23:01
 */
public class Test {

    public static void main(String[] args) {

        PurchaseReq purchaseRequest1 = new PurchaseReq(1, new BigDecimal(1000), "购买饮水机");
        PurchaseReq purchaseRequest2 = new PurchaseReq(2, new BigDecimal(6000), "购买打印机");
        PurchaseReq purchaseRequest3 = new PurchaseReq(2, new BigDecimal(30000), "购买苹果笔记本办公");

        ProjectManager projectManager = new ProjectManager("项目经理");
        DepartmentManager departmentManager = new DepartmentManager("部门经理");
        GeneralManager generalManager = new GeneralManager("总经理");
        //设置下一级处理人
        projectManager.setApprover(departmentManager);
        departmentManager.setApprover(generalManager);
        //都从项目经理开始处理
        projectManager.process(purchaseRequest1);
        projectManager.process(purchaseRequest2);
        projectManager.process(purchaseRequest3);

    }
}

测试截图

责任链模式的特点

优点

  1. 降低耦合度:将请求和处理分开,请求的发送者和接收者各个组件间完全解耦。
  2. 简化了对象:使得对象不需知道链的结构,请求者无需知道接受者,无需知道其如何处理。
  3. 增强灵活性:通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任对象。 
  4. 新增便捷性:增加新的请求处理类很方便。

缺点

  1. 因为只关心自己内部实现,不关心链内部结构,开发调试会比较麻烦。不容易确认调用的哪一个实现。
  2. 增加系统的资源消耗。因为链式调用,可能会进行很多次判断,因为每个实现都会判断是否能够处理该请求,不能处理则调用下一个,增加了系统开销。
  3. 不能保证请求被消化,因其特殊特性,在处理之前会判断是否能够处理,如果每一个链都不能处理,那么该请求无法被消化。

使用场景

  1. 有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。
  2. 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。 
  3. 可动态指定一组对象处理请求。

注意事项

  1. 合理设计责任链的节点:责任链模式的核心是将任务分解为一系列的处理节点,每个节点都有机会处理任务或将其传递给下一个节点。在设计责任链节点时,需要根据实际情况合理地划分节点责任,确保每个节点的功能清晰、独立、可扩展,并且能够按需组合形成不同的责任链。
  2. 灵活配置责任链:责任链模式支持动态配置责任链,也就是可以在运行时通过添加、移除或修改节点来构建不同的责任链。这种灵活性可以根据实际需求动态调整责任链的结构和顺序,但也需要注意避免责任链过长、过于复杂,以及节点的重叠或缺失等问题。
  3. 节点的执行顺序:责任链模式中,每个节点都有机会处理任务,但处理的顺序是非常重要的。在设计责任链时,需要仔细考虑节点的执行顺序,确保任务能够按照预期的流程依次经过每个节点,同时避免出现死循环或执行顺序混乱等问题。
  4. 避免责任链的滥用:责任链模式可以很好地解耦请求发送者和接收者之间的关系,但也容易被滥用。在应用责任链模式时,需要审慎选择,确保责任链模式能够带来真正的价值,而不是增加复杂性或降低代码可维护性。
  5. 错误处理机制:在责任链模式中,如果没有合适的节点处理任务,任务可能会无法得到处理或处理结果不符合预期。因此,在设计责任链时,需要考虑错误处理机制,例如设置默认处理节点、定义异常处理策略等,以确保任务能够得到妥善处理,并且在发生异常时能够及时进行处理和反馈。

实际应用

  1. Spring框架中的拦截器:拦截器是Spring框架中的一种常见组件,它可以在请求处理前后进行一些额外的处理,例如身份验证、日志记录、权限控制等。拦截器就是利用了责任链模式来将多个处理对象构成一条拦截器链,然后逐个处理请求。Spring框架提供了很多拦截器,例如HandlerInterceptor、WebRequestInterceptor等。
  2. Servlet中的过滤器:Servlet中的过滤器也是一种常见的使用责任链模式的场景。过滤器可以在请求处理前后进行一些额外的处理,例如安全认证、数据预处理、异常处理等。
  3. Java 8中的Lambda表达式:Java 8中的Lambda表达式可以看作是一种函数式接口,它利用责任链模式来组合、封装和传递函数对象。Lambda表达式可以通过链式结构形成一个函数的序列,然后按顺序逐个执行这些函数并返回结果,从而可以在Java中实现函数式编程。
  4. Netty中的处理器Pipeline:Netty是一种基于事件驱动的网络通信框架,它利用责任链模式和事件监听机制来处理请求。Netty中的处理器Pipeline是一条处理请求的链,该链中的每个处理器都可以对请求进行处理和传递,从而形成一个完整的事件处理流程。

更多消息资讯,请访问昂焱数据(https://www.ayshuju.com)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot整合邮件服务

SpringBoot整合邮件服务 发送邮件应该是网站的必备功能之一,什么注册验证,忘记密码或者是给用户发送营销信息。最早期的时候我们会 使用 JavaMail 相关 api 来写发送邮件的相关代码,后来 Spring 推出了 JavaMailSender 更加简化了邮件发送的…

前端下载文化部几种方法(excel,zip,html,markdown、图片等等)和导出 zip 压缩包

文章目录 1、location.href2、location.href3、a标签4、请求后端的方式5、文件下载的方式6、Blob和Base647、下载附件方法(excel,zip,html,markdown)8、封装下载函数9、导出 zip 压缩包相关方法(流方式) 总结 1、location.href //get请求 window.location.href url;2、locati…

电脑更新win10黑屏解决方法

电脑更新win10黑屏解决方法 电脑黑屏出现原因解决步骤 彻底解决 电脑黑屏 出现原因 系统未更新成功就关机,导致系统出故障无法关机 解决步骤 首先长安电源键10s关机 按电源键开机,出现logo时按F8进入安全模式。 进入自动修复环境后,单击…

freeswitch的mod_xml_curl模块

概述 freeswitch是一款简单好用的VOIP开源软交换平台。 随着fs服务的增多,每一台fs都需要在后台单独配置,耗时耗力,心力憔悴。 如果有一个集中管理配置的配置中心,统一管理所有fs的配置,并可以实现动态的修改配置就…

Linux磁盘管理

磁盘管理 基本分区管理 磁盘划分思路 进入分区表,新建分区更新分区表格式化分区表挂载使用 #lsblk #df -h 查看设备挂载情况 #fdisk -l 设备分区情况 #fdisk /dev/sdb 添加一块硬盘,需要将其分两个分区,分别格式化成ext4和vfat格式文件系…

Linux中提示No such file or directory解决方法

说明: 在linux下,./xxx.sh执行shell脚本时会提示No such file or directory。但shell明明存在,为什么就是会提示这个呢? 这种其实是因为编码方式不对,如你在win下编辑sh,然后直接复制到linux下面 实现&…

GPU版PyTorch对应安装教程

一、正确安装符合自己电脑的对应GPU版本的PyTorch之前需要了解三个基本概念 算力、CUDA driver version、CUDA runtime version ①算力:需要先知道你的显卡,之后根据官网表格进行对应,得到算力 ②CUDA driver version:电脑上显卡…

[C++]01.基础,数据类型,运算符

01.基础,数据类型,运算符 一.C基础入门1.HelloWorld2.注释3.变量4.常量5.关键字6.命名规则 二.数据类型1.整形2.sizeof关键字3.浮点型4.字符型5.转义字符6.字符串型7.布尔类型8.数据的输入 三.运算符1.算数运算符2.赋值运算符3.比较运算符4.逻辑运算符 一.C基础入门 1.HelloWo…

Java版Spring Cloud+Spring Boot+Mybatis+uniapp知识付费平台讲解+免费搭建 qt

Java版知识付费源码 Spring CloudSpring BootMybatisuniapp前后端分离实现知识付费平台 提供职业教育、企业培训、知识付费系统搭建服务。系统功能包含:录播课、直播课、题库、营销、公司组织架构、员工入职培训等。 提供私有化部署,免费售…

LBP特征笔记

LBP,局部二值模式(Local Binary Pattern),是一种描述图像局部纹理特征的方式,具有旋转不变性和灰度不变性。首先由T. Ojala, M.Pietikinen, 和 D. Harwood 在1994年提出。 LBP特征描述 基础LBP算子 基础的LBP算子定义…

【Axure教程】移动端二级滑动选择器

今天教大家制作移动端二级滑动选择器的原型模板,该原型已全国一二级省市选择器为案例,因为该原型用中继器做的,所以制作完成之后使用也很方便,只需修改中继器表格里的内容即可 一、效果展示 1. 拖动选择 2. 快捷选择 【原型预览…

s7200Smart

一、介绍 二、通讯 rs485 modbus通讯口

编辑接口和新增接口的分别调用

在后台管理系统中,有时候会碰到新增接口和编辑接口共用一个弹窗的时候. 一.场景 在点击新增或者编辑的时候都会使用这个窗口,新增直接调用接口进行增加即可,编辑则是打开这个窗口显示当前行的数据,然后调用编辑接口。 二.处理方法 在默认的情况下,这个窗口用来处理…

ansible配置文件案例

案例一 控制主机上的普通用户控制受控主机 控制端1台,受控端两台 1.将两台受控主机添加到/etc/hosts文件中 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhos…

微服务实战项目-学成在线-选课学习(支付与学习中心)模块

微服务实战项目-学成在线-选课学习(支付与学习中心)模块 1 模块需求分析 1.1 模块介绍 本模块实现了学生选课、下单支付、学习的整体流程。 网站的课程有免费和收费两种,对于免费课程学生选课后可直接学习,对于收费课程学生需要下单且支付成功方可选…

AI Chat 设计模式:10. 组合模式

本文是该系列的第十篇,采用问答式的方式展开,问题由我提出,答案由 Chat AI 作出,灰色背景的文字则主要是我的一些思考和补充。 问题列表 Q.1 给我介绍一下组合模式A.1Q.2 好的,给我举一个组合模式的例子,使…

css实现文字颜色渐变+阴影

效果 代码 <div class"top"><div class"top-text" text"总经理驾驶舱">总经理驾驶舱</div> </div><style lang"scss" scoped>.top{width: 100%;text-align: center;height: 80px;line-height: 80px;fo…

蓝桥杯上岸每日N题 第七期(小猫爬山)!!!

蓝桥杯上岸每日N题 第七期(小猫爬山)&#xff01;&#xff01;&#xff01; 同步收录 &#x1f447; 蓝桥杯上岸必背&#xff01;&#xff01;&#xff01;(第四期DFS) 大家好 我是寸铁&#x1f4aa; 冲刺蓝桥杯省一模板大全来啦 &#x1f525; 蓝桥杯4月8号就要开始了 &a…

【测试设计】性能测试工具选择:wrk?jmeter?locust?还是LR?

目录 前言 wrk 优点 缺点 jmeter 优点 缺点 locust 优点 缺点 总结 资料获取方法 前言 当你想做性能测试的时候&#xff0c;你会选择什么样的测试工具呢&#xff1f;是会选择wrk&#xff1f;jmeter&#xff1f;locust&#xff1f;还是loadrunner呢&#xff1f; 今…

opencv-29 Otsu 处理(图像分割)

Otsu 处理 Otsu 处理是一种用于图像分割的方法&#xff0c;旨在自动找到一个阈值&#xff0c;将图像分成两个类别&#xff1a;前景和背景。这种方法最初由日本学者大津展之&#xff08;Nobuyuki Otsu&#xff09;在 1979 年提出 在 Otsu 处理中&#xff0c;我们通过最小化类别内…