Java设计模式十九——责任链模式
责任链模式
老李的苦恼
每个人在出生的时候,都早已在暗中被标好了三六九等。
老李是一名建筑工地的木匠,和大多数生活在社会最底层的农民工一样,一辈子老实本分,胆小怕事。在他们的心中,谁当老爷都没有区别,世界发展如何也与他们无关,只要包工头能按时发工资,只要小家平安无事就够了,平时受点欺负,累点苦点也没办法,能忍则忍了。
并不是你安分守己,世界就会给你公平公正,社会它牢记着你的出身。
老李最近遇到了一件糟心事,起因是在工地干活的时候,被钢管砸断了鼻梁骨和颧骨,流了一个多小时血,才送到医院,包工头交了医疗费后就不再过问,老李在医院做手术加恢复总共就住了一个星期,还在流鼻血就匆匆出院,理由是怕给包工头添麻烦。
出院后一直头昏流鼻血也自己扛着,期间包工头不管不问老李身体无法支撑他出门,态度恶劣甚至辱骂让他去送材料到公司让公司报销,不送去就再也不管他。当老李问及赔偿事宜怎么处理时,包工头云淡风轻的说人现在又没事,给个万把块不就好了,老李一辈子太胆小懦弱了,不会又不敢维权,怕包工头前年和去年拖欠的工资不给自己(包工头没打欠条),自己一个人在家生闷气,好几天不吃饭。
会哭的孩子有糖吃,听话的孩子去奔涌吧。
老李就是这样的一个人,一辈子默默的吃着闷亏,遇事只知道生闷气,惩罚自己然后劝说自己妥协。这样的心态绝不止老李一个人,自古以来我们的老百姓就是这样,因为出身贱民,因为怕给任何人带去麻烦,因为经不起磨难,因为这样的人最好管理,因为你的出身就是你的原罪。
因为我曾经看见过光,所以我再也不怕黑暗。
我就是想在每篇文章的开头写一些人和事,想表达一些可以值得思考的东西。老李的家人曾经去过项目部找公司,也找过包工头,但是都没有人处理。不管哪个社会,没人没钱都不好办事,现实且残忍,如果没有关系,老李要么继续熟练的忍气吞声,要么自己一直找公司或者包工头纠缠无果。
问题分析
- 社会现实角度:老李吃了那么大的亏,现在公司和包工头都不管不问,相互踢皮球,而老李又软弱惯了,无可奈何。要怎么解决这个问题呢?老李有个亲戚老赵听到此事非常气愤,老实人就要任人宰割吗?老赵利用自己的人脉关系直接找到了公司的大老板,大老板说这事包在他身上,他让项目经理去处理,不用老李在来回跑了,等处理结果就好了。
- 我们再从技术角度分析一下,一是老李不知道具体找谁处理工伤事故,也就是找不到处理他赔偿请求的责任人,另一个就是老李需要不断的和公司或者包工头纠缠,也就是耦合性非常高,而这两点都违背了我们日常开发的设计原则。
这个时候,我们本文的重点,责任链模式就正式登场了。
责任链模式
什么是责任链模式?
责任链模式(Chain of Responsibility):使多个对象都有机会去处理请求。从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
责任链模式也叫职责链模式,属于行为型模式。通过责任链模式,可以为某个请求创建一个对象链。每个对象按照顺序检查该请求,并处理该请求,或者传给链中的下一个对象处理。
责任链模式的三个角色
责任链模式主要有以下三个角色:
- 抽象处理者角色(Handler):定义一个处理请求的接口,内部包含一个后继处理者的引用和一个处理请求的方法,抽象处理者可以是一个接口或者抽象类。
- 具体处理者角色(ConcreteHandler):实现抽象处理者。如果能够处理请求则处理,否则就将该请求转发给它的后继处理者。在具体处理者中可以访问链中下一个对象,以便请求的转发。
- 请求发送者角色:创建处理链,同时向链头的具体处理者对象提交请求,它并不关心处理细节和请求的传递过程。
责任链UML图
代码实例
上文中我们知道老李的亲戚老赵出面才摆平了此事,那老赵是怎么解决的呢?老赵找到公司的大老板,大老板让项目经理处理,项目经理让包工头或者其他人配合处理,这就形成了一个对象责任链,总有一个对象处理赔偿的请求,而老李再也不用关心具体是谁处理的工伤赔偿的请求。
下面我们用代码来演示一遍。
1、编写抽象处理者角色Handler
package com.mazhichu.designpatterns.responsibility;
import java.math.BigDecimal;
/**
* @ClassName: DealWorkInjuryRequestHandler
* @Description: 抽象处理者角色
* @Author: Moore
* @Date: 2020-06-29 9:39
* @Version: V1.0
*/
public abstract class DealWorkInjuryRequestHandler {
/**
* 如果处理不了,设置后继处理者
*/
protected DealWorkInjuryRequestHandler successor;
/**
* 处理请求的方法
* @param compensationPayments
*/
public abstract void dealWorkInjury(BigDecimal compensationPayments);
public void setSuccessor(DealWorkInjuryRequestHandler successor) {
this.successor = successor;
}
}
2、编写具体处理者角色老李的亲戚老赵。
package com.mazhichu.designpatterns.responsibility;
import java.math.BigDecimal;
/**
* @ClassName: LaoZhaoHandler
* @Description: 具体处理者角色:老赵
* @Author: Moore
* @Date: 2020-06-29 9:40
* @Version: V1.0
*/
public class LaoZhaoHandler extends DealWorkInjuryRequestHandler{
@Override
public void dealWorkInjury(BigDecimal compensationPayments) {
System.out.println("老赵:老李别担心,赔偿款一共"+compensationPayments+"元,我已经找了他们大老板去处理了。");
successor.dealWorkInjury(compensationPayments);
}
}
3、编写具体处理者角色承建公司大老板。
package com.mazhichu.designpatterns.responsibility;
import java.math.BigDecimal;
/**
* @ClassName: LaoZhaoHandler
* @Description: 具体处理者角色:承建公司大老板
* @Author: Moore
* @Date: 2020-06-29 9:40
* @Version: V1.0
*/
public class BossHandler extends DealWorkInjuryRequestHandler{
@Override
public void dealWorkInjury(BigDecimal compensationPayments) {
if(compensationPayments.compareTo(BigDecimal.valueOf(100000))>0){
System.out.println("大老板"+compensationPayments+"赔偿款,先拖拖,找人也不行。");
}else {
System.out.println("大老板"+compensationPayments+"赔偿款,才这点钱,让项目经理去处理。");
successor.dealWorkInjury(compensationPayments);
}
}
}
4、编写具体处理者角色包工头
package com.mazhichu.designpatterns.responsibility;
import java.math.BigDecimal;
import java.math.MathContext;
/**
* @ClassName: LaoZhaoHandler
* @Description: 具体处理者角色:承建公司包工头
* @Author: Moore
* @Date: 2020-06-29 9:40
* @Version: V1.0
*/
public class ContractorHandler extends DealWorkInjuryRequestHandler{
@Override
public void dealWorkInjury(BigDecimal compensationPayments) {
if(compensationPayments.compareTo(BigDecimal.valueOf(30000))>0){
System.out.println("包工头:上面压我,倒霉玩意,"+compensationPayments+"赔偿款,我要赔"+compensationPayments.multiply(BigDecimal.valueOf(0.3), MathContext.DECIMAL32));
}else {
System.out.println("包工头:上面压我,倒霉玩意,我要自己掏"+compensationPayments+"赔偿款。");
}
}
}
5、我们看看老李的维权之路是怎样的,编写客户端请求发送者角色老李。
package com.mazhichu.designpatterns.responsibility;
import java.math.BigDecimal;
/**
* @ClassName: Laoli
* @Description: 请求发送者角色:老李
* @Author: Moore
* @Date: 2020-06-29 10:44
* @Version: V1.0
*/
public class Laoli {
public static void main(String[] args) {
DealWorkInjuryRequestHandler lzHandler = new LaoZhaoHandler();
DealWorkInjuryRequestHandler bossHandler = new BossHandler();
DealWorkInjuryRequestHandler manageHandler = new ManageHandler();
DealWorkInjuryRequestHandler contractorHandler = new ContractorHandler();
lzHandler.setSuccessor(bossHandler);
bossHandler.setSuccessor(manageHandler);
manageHandler.setSuccessor(contractorHandler);
lzHandler.dealWorkInjury(BigDecimal.valueOf(120000));
System.out.println("-------------------------------------------------\n");
lzHandler.dealWorkInjury(BigDecimal.valueOf(80000));
System.out.println("-------------------------------------------------\n");
lzHandler.dealWorkInjury(BigDecimal.valueOf(20000));
}
}
6、查看运行结果:
可以看出,在代码实例中我们创建了四个处理者对象,并指定第一个处理者对象的下家是第二个处理者对象,一直到第四个处理对象包工头为止。然后客户端老李将请求传递给第一个处理者对象老赵,老李不用再关心具体是谁处理了工伤赔偿。他只知道,如果没有老赵,他最终可能只能认命,听话不闹事就能拿到工资就好。
老李是太胆小又怕事,其实他完全可以拿着伤残鉴定去劳动局监察大队去投诉,这样就会在责任链上多一个具体处理者角色,监察大队会继续追查下去,找到链上该负责的处理对象,环环相扣,最终给老李一个交代。
总结
熟悉数据结构的可以想象一下链表的结构,每一个节点都有一个指向后继节点的引用。责任链模式在我们的日常生活中也很常见,比如常见的报销或者请假流程,客户端只需要将请求提交到链上,就不用关心是哪个具体处理对象处理了请求。也可以动态的增加链上的具体处理角色,只要指定后继者处理对象就好。
适用场景
- 一个请求的处理需要多个对象当中的一个或者几个协作处理,具体哪个对象处理该请求由运行时刻自动确定。
- 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
- 可动态指定一组对象处理请求。
责任链模式优点
- 将请求的发送者和接收者解耦。
- 简化了对象。使得对象不需要知道链的结构。
- 通过改变责任链内的对象或者调动责任链的顺序,允许动态增加或者删除责任链对象。
- 在系统中增加一个新的具体请求处理者时无须修改原有系统的代码,只需要在客户端重新建链即可,从这一点来看是符合“开闭原则”的。
责任链模式缺点
- 责任链在处理请求时,可能会耗时过长。
- 责任链较长时,对象可能会涉及多个,从而影响系统运行性能,消耗内存。
- 并不保证请求一定会被执行,如果指定后继处理者不当,可能会造成死循环。
纯的与不纯的责任链模式
一个纯的责任链模式要求一个具体的处理者对象只能在两个行为中选择一个:一是承担责任,而是把责任推给下家。不允许出现某一个具体处理者对象在承担了一部分责任后又把责任向下传的情况。
在一个纯的责任链模式里面,一个请求必须被某一个处理者对象所接收;在一个不纯的责任链模式里面,一个请求可以最终不被任何接收端对象所接收。
纯的责任链模式的实际例子很难找到,一般看到的例子均是不纯的责任链模式的实现。
后话
责任链模式就讲解到这,其实很简单很好理解。难以理解的是其实老李到现在还没有处理好他的工伤赔偿事宜,不知道何时,农民工才能真正受到这个社会的尊重,不知道何时,我们才能骄傲的说我们是一个法治社会。让所有人有法可依,有理可证,有平等和公平可言。
如果可以更好,请给我光明。
如果不能更好,希望别太坏。
小惊喜
认识我的或者关注【码之初】有一段时间的朋友都知道,我是个与世无争的完全自己打理的小号主,能力一般,技术有限,坚持更新,只因热爱。没有精力和财力推广,所以也不曾盈利过,但因为同样的热爱,我们在此相遇,为了感恩这份相遇,我决定,从2020年7月1日开始,每半个月查一下后台数据,阅读最多的前三名,每人一个茶叶蛋,分享文章的前三名,依次为红牛、脉动、农夫山泉,每个月1号、16号公布结果并折现发给这些陪伴码之初的朋友,经济萧条,金额较小,承蒙不弃,皆为心意。
Java设计模式十九——责任链模式的更多相关文章
- 《java设计模式》之责任链模式
在阎宏博士的<JAVA与模式>一书中开头是这样描述责任链(Chain of Responsibility)模式的: 责任链模式是一种对象的行为模式.在责任链模式里,很多对象由每一个对象对其 ...
- 重学 Java 设计模式:实战责任链模式「模拟618电商大促期间,项目上线流程多级负责人审批场景」
作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 场地和场景的重要性 射击
- Java设计模式系列之责任链模式
责任链模式 责任链模式是一种对象的行为模式.在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出这个请求的客户端并不知道 ...
- Java设计模式学习记录-责任链模式
前言 已经把五个创建型设计模式和七个结构型设计模式介绍完了,从这篇开始要介绍行为型设计模式了,第一个要介绍的行为型设计模式就是责任链模式(又称职责链模式). 责任链模式 概念介绍 责任链模式是为了避免 ...
- 《JAVA设计模式》之责任链模式(Chain of Responsibility)
在阎宏博士的<JAVA与模式>一书中开头是这样描述责任链(Chain of Responsibility)模式的: 责任链模式是一种对象的行为模式.在责任链模式里,很多对象由每一个对象对其 ...
- Java设计模式13:责任链模式
前言 来菜鸟这个大家庭10个月了,总得来说比较融入了环境,同时在忙碌的工作中也深感技术积累不够,在优秀的人身边工作必须更加花时间去提升自己的技术能力.技术视野,所以开一个系列文章,标题就轻松一点叫做最 ...
- 设计模式(十二)职责链模式(Chain of Responsibility)(对象行为型)
设计模式(十二)职责链模式(Chain of Responsibility)(对象行为型) 1.概述 你去政府部门求人办事过吗?有时候你会遇到过官员踢球推责,你的问题在我这里能解决就解决,不能解决就 ...
- Java设计模式之《职责链模式》及应用场景
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6530089.html 职责链模式(称责任链模式)将请求的处理对象像一条长链一般组合起来,形 ...
- 设计模式 ( 十二 ) 职责链模式(Chain of Responsibility)(对象行为)
设计模式(十二)职责链模式(Chain of Responsibility)(对象行为型) 1.概述 你去政府部门求人办事过吗?有时候你会遇到过官员踢球推责,你的问题在我这里能解决就解决.不能解决就 ...
随机推荐
- DOM表单,下拉菜单和表格
DOM访问表单控件的常用属性和方法如下: action 返回该表单的提交地址 elements 返回表单内全部表单控件所组成的数组,通过数组可以访问表单内的任何表单控件. length 返回表单内表单 ...
- Java实现 LeetCode 816 模糊坐标(暴力)
816. 模糊坐标 我们有一些二维坐标,如 "(1, 3)" 或 "(2, 0.5)",然后我们移除所有逗号,小数点和空格,得到一个字符串S.返回所有可能的原始 ...
- Java实现 LeetCode 687 最长同值路径(递归)
687. 最长同值路径 给定一个二叉树,找到最长的路径,这个路径中的每个节点具有相同值. 这条路径可以经过也可以不经过根节点. 注意:两个节点之间的路径长度由它们之间的边数表示. 示例 1: 输入: ...
- Java实现 洛谷 P1914 小书童——密码
import java.util.Scanner; public class Main { private static Scanner cin; public static void main(St ...
- java实现第三届蓝桥杯数据压缩
数据压缩 某工业监控设备不断发回采样数据.每个数据是一个整数(0到1000之间).各个数据间用空白字符(空格,TAB或回车换行)分隔.这些数据以文本形式被存储在文件中. 因为大多数时候,相邻的采样间隔 ...
- 从零搭建Window前端开发环境
前言 作为一个小前端,是否因为搭建环境烦恼过,是否因为npm等国外镜像踩坑过,不要怕,接下来跟着我一步步搭建适合自己的开发环境吧!!! node 这个不用说了吧,我们经常和他打交道,无论是 gulp. ...
- opencl(6)读写传输命令、内存映射命令
1:将缓存对象的内容读到缓存对象中(从设备到主机) cl_int clEnqueuReadBuffer( cl_command_queue command_queue, //命令队列 cl_mem b ...
- 2.keras-构建基本网络实现非线性回归
构建基本网络实现非线性回归 1.加载显示数据集 import tensorflow as tf import numpy as np import keras from keras.layers im ...
- IDEA环境Spring Boot 2.3整合Activiti 6.0,启动项目初始化表并创建核心服务
如下步骤照着抄就完事了. 一.新建一个spring boot项目,并引入相关依赖 <?xml version="1.0" encoding="UTF-8" ...
- EIGRP-16-其他和高级的EIGRP特性-2-非等价负载分担
与大多数内部路由协议不同的是, EIGRP能够将流量负载分到多条非等价路径上,而不仅仅使用去往目的地最近距离的那一条路径.提供这项功能的特性称为非等价负载分担. 非等价负载分担的核心概念是可行后继 ...