Java描述设计模式(15):责任链模式
本文源码:GitHub·点这里 || GitEE·点这里
一、生活场景描述
1、请假审批流程
公司常见的请假审批流程:请假天数
当 day<=3 天,项目经理审批
当 3<day<=5 天,部门经理审批
当 day>5 天,CEO审批
2、流程图解

3、代码实现
public class C01_InScene {
public static void main(String[] args) {
// 组装责任链
AuditHandler h1 = new CeoManger();
AuditHandler h2 = new DeptManger();
AuditHandler h3 = new ProjectManger();
h3.setSuccessor(h2);
h2.setSuccessor(h1);
/*
* 测试输出
* 项目经理无权审批
* 部门经理无权审批
* CEO审批:同意【Cicada】,请假【6】天
*/
h3.handleLeaveDay("Cicada",6);
}
}
abstract class AuditHandler {
//持有下一个处理请求的对象
protected AuditHandler successor = null;
public AuditHandler getSuccessor() {
return successor;
}
public void setSuccessor(AuditHandler successor) {
this.successor = successor;
}
public abstract void handleLeaveDay (String user,Integer day);
}
/**
* 项目经理审批
*/
class ProjectManger extends AuditHandler{
@Override
public void handleLeaveDay(String user, Integer day) {
if (day <= 3){
System.out.println("项目经理审批:同意【"+user+"】,请假【"+day+"】天");
} else {
System.out.println("项目经理无权审批");
if (getSuccessor() != null){
getSuccessor().handleLeaveDay(user,day);
}
}
}
}
/**
* 部门经理审批
*/
class DeptManger extends AuditHandler{
@Override
public void handleLeaveDay(String user, Integer day) {
if (day > 3 && day <= 5){
System.out.println("部门经理审批:同意【"+user+"】,请假【"+day+"】天");
} else {
System.out.println("部门经理无权审批");
if (getSuccessor() != null){
getSuccessor().handleLeaveDay(user,day);
}
}
}
}
/**
* CEO审批
*/
class CeoManger extends AuditHandler{
@Override
public void handleLeaveDay(String user, Integer day) {
if (day > 5){
System.out.println("CEO审批:同意【"+user+"】,请假【"+day+"】天");
} else {
if (getSuccessor() != null){
getSuccessor().handleLeaveDay(user,day);
}
}
}
}
二、责任链模式
1、基础概念
责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下个的引用而连接起来形成一条链式结构。请求在这个链上传递,直到链上的某一个对象有权处理该请求。请求的客户端不知道链上的哪个对象处理该请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任对象。
2、核心角色
(1)、抽象处理者角色
定义处理请求的接口。接口可以也可以给出一个方法以设定和返回对下个对象引用。这个角色通常由一个Java抽象类或者Java接口实现。
(2)、具体处理者角色
具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下个对象。由于具体处理者持有对下家的引用。
3、模式图解

4、源代码实现
public class C02_Chain {
public static void main(String[] args) {
// 组装责任链
Handler handler1 = new ConcreteHandler();
Handler handler2 = new ConcreteHandler();
handler1.setHandler(handler2);
// 提交请求
handler1.handlerRequest();
}
}
/**
* 抽象处理者角色
*/
abstract class Handler {
/*
* 持有后续的责任对象
*/
protected Handler handler;
/**
* 处理请求的方法
*/
public abstract void handlerRequest();
public Handler getHandler() {
return handler;
}
public void setHandler(Handler handler) {
this.handler = handler;
}
}
/**
* 具体处理者角色
*/
class ConcreteHandler extends Handler{
/**
* 调用该方法处理请求
*/
@Override
public void handlerRequest() {
/*
* 判断是否有后续的责任对象,没有就出来请求,有就直接放过
*/
if(getHandler() != null){
System.out.println("放过请求,下个对象处理...");
getHandler().handlerRequest();
} else{
System.out.println("直接处理请求了...");
}
}
}
三、Spring框架应用
1、DispatcherServlet类的
DispatcherServlet 核心方法 doDispatch。HandlerExecutionChain只是维护HandlerInterceptor的集合,可以向其中注册相应的拦截器,本身不直接处理请求,将请求分配给责任链上注册处理器执行,降低职责链本身与处理逻辑之间的耦合程度。
HandlerExecutionChain mappedHandler = null;
mappedHandler = this.getHandler(processedRequest);
mappedHandler.applyPreHandle(processedRequest, response);
mappedHandler.applyPostHandle(processedRequest, response, mv);
2、HandlerExecutionChain类
这里分析的几个方法,都是从DispatcherServlet类的doDispatch方法中请求的。
- 获取拦截器,执行preHandle方法。
boolean applyPreHandle(HttpServletRequest request,
HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
this.triggerAfterCompletion(request, response, (Exception)null);
return false;
}
}
}
return true;
}
- 在applyPreHandle方法中,执行triggerAfterCompletion方法。
void triggerAfterCompletion(HttpServletRequest request,
HttpServletResponse response, Exception ex) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = this.interceptorIndex; i >= 0; --i) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
} catch (Throwable var8) {
logger.error("HandlerInterceptor.afterCompletion threw exception", var8);
}
}
}
}
- 获取拦截器,执行applyPostHandle方法。
void applyPostHandle(HttpServletRequest request,
HttpServletResponse response, ModelAndView mv)
throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = interceptors.length - 1; i >= 0; --i) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
四、模式总结
- 将请求和处理逻辑分开,实现解耦提高系统的灵活性;
- 当责任链过长时,性能会下降,测试也会变得复杂;
- 应用场景:请假、加薪、费用等常见的审批流程;
五、源代码地址
GitHub·地址
https://github.com/cicadasmile/model-arithmetic-parent
GitEE·地址
https://gitee.com/cicadasmile/model-arithmetic-parent

Java描述设计模式(15):责任链模式的更多相关文章
- Java常见设计模式之责任链模式
原文地址: http://www.cnblogs.com/java-my-life/archive/2012/05/28/2516865.html 在阎宏博士的<JAVA与模式>一书中开 ...
- 乐在其中设计模式(C#) - 责任链模式(Chain of Responsibility Pattern)
原文:乐在其中设计模式(C#) - 责任链模式(Chain of Responsibility Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 责任链模式(Chain of R ...
- php设计模式之责任链模式
php设计模式之责任链模式 实际问题 你的论坛有举报功能,版主能解决粗口方面的举报,警察能解决严重一点的黄赌毒方面的举报,更严重的反政府的举报就需要由国安局来完成. 职场中每个人都有直属的上级,如果到 ...
- python设计模式之责任链模式
python设计模式之责任链模式 开发一个应用时,多数时候我们都能预先知道哪个方法能处理某个特定请求.然而,情况并非总是如此.例如,想想任意一种广播计算机网络,例如最早的以太网实现.在广播计算机网络中 ...
- 设计模式之责任链模式——Java语言描述
责任链模式为请求创建了一个接受者对象的链.这种模式给予请求的类型,对请求的发送者和接受者进行解耦.这种类型的设计模式属于行为模式.在这种模式下,通常每个接收者都包含对另一个接收者的引用.如果一个对象不 ...
- 详解java设计模式之责任链模式
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt175 从击鼓传花谈起 击鼓传花是一种热闹而又紧张的饮酒游戏.在酒宴上宾客依次 ...
- JAVA设计模式之责任链模式
在阎宏博士的<JAVA与模式>一书中开头是这样描述责任链(Chain of Responsibility)模式的: 责任链模式是一种对象的行为模式.在责任链模式里,很多对象由每一个对象对其 ...
- Java进阶篇设计模式之八 ----- 责任链模式和命令模式
前言 在上一篇中我们学习了结构型模式的享元模式和代理模式.本篇则来学习下行为型模式的两个模式, 责任链模式(Chain of Responsibility Pattern)和命令模式(Command ...
- Java设计模式应用——责任链模式
生产一个产品,需要依次执行多个步骤,才能完成,那么是使用责任链模式则是极好的. 在性能告警模块开发过程中,创建一条告警规则需要执行阈值解析,中间表生成,流任务生成,规则入库,告警事件入库等诸多操作.如 ...
随机推荐
- oracle用imp导入dmp文件
oracle命令行登录 sqlplus 用户名/密码 创建用户 create user 用户 identified by 密码 ; 创建表空间 create tablespace 表空间名 dataf ...
- 微软发布.Net Core 3.0 RC1,最终版本定于9月23日
2019.9.17 微软 宣布推出.NET Core 3.0 Release Candidate 1.就像Preview 9一样,主要专注于为 .NET Core 3.0 发布最终版本 .现在变得非常 ...
- JAVA集合框架包含的内容
Java集合框架提供了一套性能优良.使用方便的接口和类,他们位于java.util包中. Collection接口 主要有List.Set等实现类,Map接口主要有HashMap.TreeMap等实现 ...
- 搜索入门练习题9 LETTERS 题解
题目出处:<信息学奥赛一本通>第五章上机练习1 或者 POJ1154 题目描述 给出一个 \(R\times S\) 的大写字母矩阵,一开始你所处的位置在左上角,你可以向上下左右四个方向移 ...
- Day 10 用户的提权,用户组的创建删除
1.如何为用户设定密码,又如何修改密码? 2.用户的创建流程? [扩展了解] 3.用户组如何管理? 4.普通用户无权限怎么办? 切换身份 or 提权? su 切换用户 sudo 提权 5.为用户添 ...
- 采用WPF技术,开发OFD电子文档阅读器
前言 OFD是国家标准版式文档格式,于2016年生效.OFD文档国家标准参见<电子文件存储与交换格式版式文档>.既然是国家标准,OFD随后肯定会首先在政务系统使用,并逐步推向社会各个方面. ...
- Ext.js中树勾选的四种操作
最近在做控件优化的时候产品提了一个需求,对树的勾选要满足四种勾选方案: 1.点击一次根节点,当根节点和子节点均未选中的情况下,根节点和子节点全都选中. 2.第二次点击根节点,当根节点和部分或全部子节点 ...
- FPGA 内部详细架构你明白了吗?
FPGA 芯片整体架构如下所示,大体按照时钟域划分的,即根据不同的工艺.器件速度和对应的时钟进行划分: FPGA 内部详细架构又细分为如下六大模块: 1.可编程输入输出单元(IOB)(Input Ou ...
- Spring MVC-从零开始-view-forward、redirect
1.forward或redirect后,不再走viewResolver过程,直接重新从控制器开始 2.代码 package com.jt; import org.springframework.ste ...
- 『TensorFlow2.0正式版教程』极简安装TF2.0正式版(CPU&GPU)教程
0 前言 TensorFlow 2.0,今天凌晨,正式放出了2.0版本. 不少网友表示,TensorFlow 2.0比PyTorch更好用,已经准备全面转向这个新升级的深度学习框架了. 本篇文章就 ...