Java设计模式-职责链模式

1 概述

在现实生活中,常常会出现这样的事例:一个请求有多个对象可以处理,但每个对象的处理条件或权限不同。例如,公司员工请假,可批假的领导有部门负责人、副总经理、总经理等,但每个领导能批准的天数不同,员工必须根据自己要请假的天数去找不同的领导签名,也就是说员工必须记住每个领导的姓名、电话和地址等信息,这增加了难度。这样的例子还有很多,如找领导出差报销、生活中的“击鼓传花”游戏等。

定义:

又名职责链模式,为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。

2 结构

职责链模式主要包含以下角色:

  • 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
  • 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
  • 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。

3 案例实现

在这里插入图片描述
代码如下:

//请假条
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;}public String getName() {return name;}public int getNum() {return num;}public String getContent() {return content;}
}//处理者抽象类
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) {this.numStart = numStart;}//设置请假天数范围public Handler(int numStart, int numEnd) {this.numStart = numStart;this.numEnd = numEnd;}//设置上级领导public void setNextHandler(Handler nextHandler){this.nextHandler = nextHandler;}//提交请假条public final void submit(LeaveRequest leave){if(0 == this.numStart){return;}//如果请假天数达到该领导者的处理要求if(leave.getNum() >= this.numStart){this.handleLeave(leave);//如果还有上级 并且请假天数超过了当前领导的处理范围if(null != this.nextHandler && leave.getNum() > numEnd){this.nextHandler.submit(leave);//继续提交} else {System.out.println("流程结束");}}}//各级领导处理请假条方法protected abstract void handleLeave(LeaveRequest leave);
}//小组长
public class GroupLeader extends Handler {public GroupLeader() {//小组长处理1-3天的请假super(Handler.NUM_ONE, Handler.NUM_THREE);}@Overrideprotected void handleLeave(LeaveRequest leave) {System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");System.out.println("小组长审批:同意。");}
}//部门经理
public class Manager extends Handler {public Manager() {//部门经理处理3-7天的请假super(Handler.NUM_THREE, Handler.NUM_SEVEN);}@Overrideprotected void handleLeave(LeaveRequest leave) {System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");System.out.println("部门经理审批:同意。");}
}//总经理
public class GeneralManager extends Handler {public GeneralManager() {//部门经理处理7天以上的请假super(Handler.NUM_SEVEN);}@Overrideprotected void handleLeave(LeaveRequest leave) {System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");System.out.println("总经理审批:同意。");}
}//测试类
public class Client {public static void main(String[] args) {//请假条来一张LeaveRequest leave = new LeaveRequest("小花",5,"身体不适");//各位领导GroupLeader groupLeader = new GroupLeader();Manager manager = new Manager();GeneralManager generalManager = new GeneralManager();
​groupLeader.setNextHandler(manager);//小组长的领导是部门经理manager.setNextHandler(generalManager);//部门经理的领导是总经理//之所以在这里设置上级领导,是因为可以根据实际需求来更改设置,如果实战中上级领导人都是固定的,则可以移到领导实现类中。//提交申请groupLeader.submit(leave);}
}

4 优缺点

1,优点:

降低了对象之间的耦合度

该模式降低了请求发送者和接收者的耦合度。

增强了系统的可扩展性

可以根据需要增加新的请求处理类,满足开闭原则。

增强了给对象指派职责的灵活性

当工作流程发生变化,可以动态地改变链内的成员或者修改它们的次序,也可动态地新增或者删除责任。

责任链简化了对象之间的连接

一个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句。

责任分担

每个类只需要处理自己该处理的工作,不能处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。

2,缺点:

不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。

5 源码解析

在javaWeb应用开发中,FilterChain是职责链(过滤器)模式的典型应用,以下是Filter的模拟实现分析:

模拟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 {@Overridepublic void doFilter(Request request, Response response, FilterChain chain) {System.out.println("过滤器1 前置处理");// 先执行所有request再倒序执行所有responsechain.doFilter(request, response);System.out.println("过滤器1 后置处理");}
}public class SecondFilter  implements Filter {@Overridepublic void doFilter(Request request, Response response, FilterChain chain) {System.out.println("过滤器2 前置处理");// 先执行所有request再倒序执行所有responsechain.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++;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.hqwc.cn/news/83634.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

无涯教程-进程 - 内存映射

mmap()系统调用提供了将文件或设备映射到内存的调用进程的虚拟地址空间中的映射。这有两种类型- 文件映射 - 此映射将进程的虚拟内存区域映射到文件&#xff0c;这意味着读取或写入那些内存区域会导致文件被读取或写入&#xff0c;这是默认的映射类型。 匿名映射 - 此映射…

C语言_分支和循环语句(1)

文章目录 前言分支语句循环语句一、什么是语句1.C语句可分为以下五类&#xff1a;2. 控制语句3.以下三类&#xff1a; 二、分支语句&#xff08;选择结构&#xff09;2.1 .1 if语句语法结构2.1.2 if书写形式的对比2.1.3 练习2.2 switch 语句 2.2.1 在switch语句中的break2.2.2 …

java八股文面试[JVM]——JVM调优

知识来源&#xff1a; 【2023年面试】JVM性能调优实战_哔哩哔哩_bilibili

ImportError: cannot import name ‘SQLDatabaseChain‘ from ‘langchain‘解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

一文了解BFD技术:实现故障快速检测!

一、概诉 BFD提供了一个通用的、标准化的、介质无关的、协议无关的快速故障检测机制&#xff0c;有以下两大优点&#xff1a; 1.对相邻转发引擎之间的通道提供轻负荷、快速故障检测。 2.用单一的机制对任何介质、任何协议层进行实时检测。 BFD是一个简单的“Hello”协议。两个…

vue关闭弹窗刷新父页面 this.$refs

代码截图 主页面 弹出框页面 接这一篇文章后续 参考链接

Arduino驱动四位0.36英寸共阴数码管模块

目录 一、简介二、参数性能三、电路原理图四、使用方法 一、简介 点击图片购买 四位0.36英寸共阴数码管模块由一个12引脚的0.36英寸红色共阴数码管和一个TM1650驱动芯片构成&#xff0c;大大减少了驱动引脚与连线&#xff0c;只需要四根引线IIC即可控制数码管的显示。TM11650是…

【C++进阶(一)】STL大法以及string的使用

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:C从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习C   &#x1f51d;&#x1f51d; STL标准库 1. 前言2. STL库的版本以及缺陷3. ST…

浅析阿里云灵积(平台)模型服务

简介&#xff1a; DashScope灵积模型服务以模型为中心&#xff0c;致力于面向AI应用开发者提供品类丰富、数量众多的模型选择&#xff0c;并为其提供开箱即用、能力卓越、成本经济的模型服务API。DashScope灵积模型服务依托达摩院等机构的优质模型&#xff0c;在阿里云基础设施…

opencv 案例实战02-停车场车牌识别SVM模型训练及验证

1. 整个识别的流程图&#xff1a; 2. 车牌定位中分割流程图&#xff1a; 三、车牌识别中字符分割流程图&#xff1a; 1.准备数据集 下载车牌相关字符样本用于训练和测试&#xff0c;本文使用14个汉字样本和34个数字跟字母样本&#xff0c;每个字符样本数为40&#xff0c;样本尺…

如何使用CSS实现一个3D旋转效果?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 3D效果实现⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域…

【C++奇遇记】函数模板

&#x1f3ac; 博客主页&#xff1a;博主链接 &#x1f3a5; 本文由 M malloc 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f384; 学习专栏推荐&#xff1a;LeetCode刷题集 数据库专栏 初阶数据结构 &#x1f3c5; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如…