【Java设计模式】十六、责任链模式

news2024/12/24 3:03:12

文章目录

  • 1、责任链模式
  • 2、案例:批假
  • 3、在源码中的实际应用

1、责任链模式

一个请求可以有多个对象处理,但这些对象能处理的权限不同。比如公司请假,部门负责人、副经理、经理都能批,但他们能批的最大天数不一样。每次让员工直接找自己请假天数对应领导,很麻烦。员工要记录所有信息不说,任何一个领导权限变更,员工记录的信息都要跟着变。因此,考虑如下改进:

在这里插入图片描述

三个请求处理者(领导)连成一条线,现在张三来请假,只需找其部分负责人即可,部门负责人看张三请假的天数,自己能批准就批准,不能批准就找他自己的上级(副总经理),以此类推。

责任链模式,即:为了避免请求发送者和多个请求处理者耦合在一起,让所有请求处理者通过下一对象的引用连成一条链。请求过来,沿着这条链走,直到有对象处理它。

结构角色:

  • 抽象处理者:接口或抽象类,包含抽象处理方法 + 一个后继连接
  • 具体处理者:实现上面的抽象处理方法,判断能否处理本次请求,能则处理,不能则将请求转给后继者
  • 客户类:创建处理链,向链头的具体处理者提交请求,但不用关系请求的传递过程

2、案例:批假

需求:请假流程控制,一天以下只需小组长同意,1到3天需要部门经理同意,3到7天需要总经理同意。很明显,请求有多个处理者,且处理的范围和权限不同 ⇒ 责任链

在这里插入图片描述

先定义请假条这个业务类

//请假条
@Getter
public class LeaveRequest {
    private String name;//姓名
    private int num;//请假天数
    private String content;//请假内容

    public LeaveRequest(String name, int num, String content) {  //有参构造完成初始化
        this.name = name;
        this.num = num;
        this.content = content;
    }
}

定义抽象处理者类,除了业务属性外,里面有一个后继者属性。注意两个方法:

  • 抽象方法:给各个处理请求的类去继承实现
  • 一个后继连接方法:final修饰,定好处理逻辑
//处理者抽象类
public abstract class Handler {

	//常量
    protected final static int NUM_ONE = 1;
    protected final static int NUM_THREE = 3;
    protected final static int NUM_SEVEN = 7;

    //该领导处理的请假天数区间
    private int numStart;
    private int numEnd;

    //领导上面还有领导(后继者)
    private Handler nextHandler;

    //设置请假天数范围
    public Handler(int numStart, int numEnd) {
        this.numStart = numStart;
        this.numEnd = numEnd;
    }

    //设置上级领导
    public void setNextHandler(Handler nextHandler){
        this.nextHandler = nextHandler;
    }

	!!!抽象方法
	//各级领导处理请假条方法
    protected abstract void handleLeave(LeaveRequest leave);
    
    !!!final方法
    //提交请假条(final的,子类不能重写)
    public final void submit(LeaveRequest leave){
        //如果请假天数达到该领导者的处理要求
        if(leave.getNum() >= this.numStart){
            this.handleLeave(leave);

            //如果还有上级 并且请假天数超过了当前领导的处理范围
            if(null != this.nextHandler && leave.getNum() > numEnd){
                this.nextHandler.submit(leave);//继续提交!!!
            } else {
                System.out.println("流程结束");
            }
        }
    }

    
}

定义具体的处理者,继承抽象处理:小组长

//小组长
public class GroupLeader extends Handler {
    public GroupLeader() {
        //小组长处理0-1天的请假
        super(0, Handler.NUM_ONE);
    }

    @Override
    protected void handleLeave(LeaveRequest leave) {
        System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
        System.out.println("小组长审批:同意。");
    }
}

具体处理者:部门经理

//部门经理
public class Manager extends Handler {
    public Manager() {
        //部门经理处理1-3天的请假
        super(Handler.NUM_ONE, Handler.NUM_THREE);
    }

    @Override
    protected void handleLeave(LeaveRequest leave) {
        System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
        System.out.println("部门经理审批:同意。");
    }
}

具体处理者:总经理

//总经理
public class GeneralManager extends Handler {
    public GeneralManager() {
        //部门经理处理3-7天的请假
        super(Handler.NUM_THREE, Handler.NUM_SEVEN);
    }

    @Override
    protected void handleLeave(LeaveRequest leave) {
        System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
        System.out.println("总经理审批:同意。");
    }
}

测试,这里创建各级领导对象,并set他们的NextHandler属性,建立起责任链。如果实战中上级领导人都是固定的,则可以移到领导实现类中去Set。

//测试类
public class Client {
    public static void main(String[] args) {
        //请假条来一张
        LeaveRequest leave = new LeaveRequest("小明",1,"身体不适");

        //各位领导
        GroupLeader groupLeader = new GroupLeader();
        Manager manager = new Manager();
        GeneralManager generalManager = new GeneralManager();
		
		//建立责任链
        groupLeader.setNextHandler(manager);//小组长的领导是部门经理
        manager.setNextHandler(generalManager);//部门经理的领导是总经理
        //之所以在这里设置上级领导,是因为可以根据实际需求来更改设置,如果实战中上级领导人都是固定的,则可以移到领导实现类中。

        //提交申请(找责任链的链头处理者)
        groupLeader.submit(leave);
    }
}

运行:

在这里插入图片描述

如此实现,扩展性强很强:如果以后要加个总监审批,那就再定义个具体处理者类,set进责任链即可。也可动态删除某个处理者。

3、在源码中的实际应用

模拟示意责任链模式在JavaWeb源码中的应用。先写接口模拟web请求对象Request和web响应对象Response:

public interface Request{
 
}

public interface Response{
 
}

模拟web过滤器Filter:

public interface Filter {
	public void doFilter(Request req,Response res,FilterChain c);
}

两个具体的过滤器:

public class FirstFilter implements Filter {
   @Override
   public void doFilter(Request request, Response response, FilterChain chain) {

       System.out.println("过滤器1 前置处理");

       // 先执行所有request再倒序执行所有response
       chain.doFilter(request, response);

       System.out.println("过滤器1 后置处理");
   }
}

public class SecondFilter  implements Filter {
   @Override
   public void doFilter(Request request, Response response, FilterChain chain) {

       System.out.println("过滤器2 前置处理");

       // 先执行所有request再倒序执行所有response
       chain.doFilter(request, response);

       System.out.println("过滤器2 后置处理");
   }
}

过滤器链类FilterChain:

public class FilterChain {

    private List<Filter> filters = new ArrayList<Filter>();

    private int index = 0;

    // 链式调用
    public FilterChain addFilter(Filter filter) {
        this.filters.add(filter);
        return this;
    }

    public void doFilter(Request request, Response response) {
        if (index == filters.size()) {
            return;
        }
        Filter filter = filters.get(index);
        index++;
        //调用过滤器链里每个子过滤器重写的doFilter方法
        filter.doFilter(request, response, this);
    }
}

测试类:

public class Client {
    public static void main(String[] args) {
        Request  req = null;   //占位
        Response res = null ;
		//过滤器链
        FilterChain filterChain = new FilterChain();
        //添加过滤器
        filterChain.addFilter(new FirstFilter()).addFilter(new SecondFilter());
        filterChain.doFilter(req,res);
    }
}

在这里插入图片描述

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

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

相关文章

加密与安全_PGP、OpenPGP和GPG加密通信协议

文章目录 PGPOpenPGPGPG工作原理工作流程用途案例说明过程 代码实现pom依赖PgpEncryptionUtilPgpDecryptionUtilCommonUtilsPgpEncryptionTest 小结 PGP PGP (Pretty Good Privacy) 是一种加密通信协议&#xff0c;用于保护电子邮件和文件的安全性和隐私。它通过使用加密、数字…

福派斯狗粮质量怎么样?

亲爱的宠物家长们&#xff0c;你们是不是也在为选择一款高质量的狗粮而犯愁呢&#xff1f;今天&#xff0c;我要和大家分享一下福派斯狗粮的质量问题&#xff0c;希望能够为你们提供一些参考。 &#x1f43e; 首先&#xff0c;让我们来聊聊福派斯狗粮的原材料。福派斯狗粮选用的…

机器学习模型—支持向量机 (SVM)

机器学习模型—支持向量机 (SVM) 支持向量机 (SVM) 是一种强大的机器学习算法,用于线性或非线性分类、回归,甚至异常值检测任务。SVM 可用于各种任务,例如文本分类、图像分类、垃圾邮件检测、笔迹识别、基因表达分析、人脸检测和异常检测。SVM 在各种应用中具有适应性和高效…

【VUe】简略学习 vue

Vue 是一套用于构建用户界面的渐进式框架。要想使用这个框架&#xff0c;就需要先在页面中引用&#xff1a; 如何使用&#xff1a; 来到控制台&#xff1a; 数据绑定 若要在标签里替换&#xff0c;就需要使用 v-bind 指令了&#xff1a; 在标签里&#xff08;尖括号里&#xf…

jpg 转 ico 强大的图片处理工具 imageMagick

点击下载 windows, mac os, linux版本 GitHub - ImageMagick/ImageMagick: &#x1f9d9;‍♂️ ImageMagick 7 1. windows程序 链接&#xff1a;https://pan.baidu.com/s/1wZLqpcytpCVAl52pIrBBEw 提取码&#xff1a;hbfy 一直点击下一步安装 2. 然后 winr键 打开cmd 然…

软文推广怎么做效果更好?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 软文推广想要效果好&#xff0c;你可以这么做&#xff1a; 1. 选对平台很重要 首先&#xff0c;你得找准你的目标受众喜欢去哪&#xff0c;然后就去那儿发软文。别盲目乱投&#xff0c;…

【计算机网络】1.5 分组交换网中的时延、丢包和吞吐量

A.分组交换网中的时延 当分组从一个节点沿着路径到后一节点时&#xff0c;该分组在沿途的各个节点经受了几种不同类型的时延。 时延的类型 处理时延 - d n o d a l d_{nodal} dnodal​ 处理时延包括以下部分—— a. 检查分组首部 b. 决定分组导向 排队时延 - d p r o c d_{…

原生JavaScript,根据后端返回扁平JSON动态【动态列头、动态数据】生成表格数据

前期准备&#xff1a; JQ下载地址&#xff1a; https://jquery.com/ <!DOCTYPE html> <html><head><meta charset"utf-8"><title>JSON动态生成表格数据,动态列头拼接</title><style>table {width: 800px;text-align: cen…

2.1 塑性力学——应力分析基本概念

个人专栏—塑性力学 1.1 塑性力学基本概念 塑性力学基本概念 1.2 弹塑性材料的三杆桁架分析 弹塑性材料的三杆桁架分析 1.3 加载路径对桁架的影响 加载路径对桁架的影响 目录 个人专栏—塑性力学 应力 \color{blue}应力 应力&#xff1a;内力的分布集度 单元体 \color{blue}单…

C++初学

1>思维导图 2>试编程 提示并输入一个字符串&#xff0c;统计该字符中大写、小写字母个数、数字个数、空格个数以及其他字符个数要求使用C风格字符串完成 #include <iostream> #include<string.h> using namespace std;int main() {string str;cout <<…

选择短信群发平台要小心陷阱

你知道短信群发平台也有陷阱吗&#xff1f;选择短信群发平台很重要&#xff0c;今天小编就为您介绍短信群发平台有哪些陷阱&#xff1f; 这几点你要注意了&#xff1a; 1、扣量&#xff0c;有些不靠谱的短信群发平台开始以低价诱惑“客户”&#xff0c;但是发送过程中就暗中扣…

不锈钢电阻器-栅极电阻器 - 为什么要使用它们呢?

常规 如果你看一个典型的吉他放大器的原理图&#xff0c;你会注意到有一个电阻器与第一个电子管的栅极串联&#xff0c;通常在68K左右&#xff0c;还有一个电阻器与功率管的栅极串联&#xff0c;通常为1.5K或5.6K&#xff0c;你可能会偶尔看到非常大的电阻&#xff0c; 例如 4…

学习JavaEE日子 Day24 TreeSet,内置比较器,外置比较器,HashMap

Day24 TreeSet 1.TreeSet 1.1 TreeSet的使用 注意&#xff1a;TreeSet的使用和HashSet一样 public class Test01 {public static void main(String[] args) {//创建TreeSet集合的对象TreeSet<String> set new TreeSet<>();//添加元素set.add("麻生希"…

Excel生成 chart 混合图表

在开发中有这样一个需求&#xff0c;邮件预警的时候&#xff0c;要求邮件主体内容是一个Chart 图表&#xff08;生成后的img&#xff09;&#xff0c;邮件需要有附件&#xff0c;且附件是Excel列表加图表&#xff0c;图表类型是混合图。 回顾&#xff1a;在之前一篇讲到如何使用…

Java中 常见的开源图库介绍

阅读本文之前请参阅------Java中 图的基础知识介绍 在 Java 中&#xff0c;有几种流行的开源图库&#xff0c;它们提供了丰富的图算法和高级操作&#xff0c;可以帮助开发者更高效地处理图相关的问题。以下是几种常见的 Java 图库及其特点和区别&#xff1a; JGraphT …

【C++】---string的OJ题

【C】---string的OJ题 1.字符串转整形数字&#xff08;重要&#xff09;&#xff08;1&#xff09;题目描述&#xff08;2&#xff09;思路展示&#xff08;3&#xff09;代码实现 2.字符串相加&#xff08;重要&#xff09;&#xff08;1&#xff09;题目描述&#xff08;2&am…

vim使用命令

1、 复制粘贴 复制一行: yy p vim 1.txt 进入编辑模式&#xff0c;在需要复制的行先按两下y键&#xff0c;再按p就完成复制复制2行&#xff1a; 2yy p 复制n行&#xff1a; nyy p 2、 删除 删除一行: dd删除2行: 2dd删除n行: ndd 3、 撤销 撤销上一步操作&#xff1a;…

【三、接口协议与抓包】使用ApiPost进行接口测试

你好&#xff0c;我是山茶&#xff0c;一个探索AI 测试的程序员。 接口测试是测试系统组件间接口的一种测试。接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。测试的重点是要检查数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及系统间的相…

前端javascript Promise使用方法详解(非常全面)

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属的专栏&#xff1a;前端零基础教学&#xff0c;实战进阶 景天的主页&#xff1a;景天科技苑 文章目录 Promise对象&#xff08;1&#xff09;…

鸿蒙开发:从入门到精通的全方位学习指南

随着华为鸿蒙HarmonyOS生态系统的迅速扩展&#xff0c;越来越多的开发者渴望深入了解并掌握这一前沿技术。本文旨在为鸿蒙开发新手提供一份详尽且实用的学习教程&#xff0c;助您从零开始&#xff0c;逐步迈向鸿蒙开发的巅峰。 一、鸿蒙开发环境搭建 DevEco Studio安装&#x…