责任链模式
概述
首先我们了解一下什么是“推卸责任”,假设去某购物网站咨询售后问题,首先售前客服会让你联系售后客服,连续售后客服后会让你联系产品质量客服等等,就像被踢皮球一样踢来踢去。推卸责任有点贬义词的意思,但这有利于我们更快的理解责任链模式。
在责任链模式中,每一个处理人只负责它可以处理的问题,如果这个问题处理不了,则推给下一个人,下一个人再处理不了再推给下下个人…这就是责任链模式。
示例程序
在此章节中,我们举一个更贴近生活的例子,公司采购某产品,需要经过3级领导审批,如果价格大于1000块,还需要经过2级领导审批,如果价格大于10000块,还需要1级领导审批。
基础代码
AuthService作为一个审核服务类,将审核的数据存入到map中
public class AuthService {
private static Map<String, Date> map = new HashMap<>();
public static Date queryAuthInfo(String uId,String orderId){
return map.get(uId.concat(orderId));
}
public static void setAuthInfo(String uId,String orderId){
map.put(uId.concat(orderId),new Date());
}
}
返回类
@Data
public class AuthInfo {
private String code;
private String info = "";
public AuthInfo(String code, String ...infos) {
this.code = code;
for (String str:infos){
this.info = this.info.concat(str);
}
}
}
不使用设计模式实现
将三层审批写在同一个方法中,虽然可以实现对应的功能,但是不遵循开闭原则,对修改很不方便
@Slf4j
public class AuthController {
public AuthInfo doAuth(String uId,String orderId,Integer authInt){
//三级审批
Date date = AuthService.queryAuthInfo("10003", orderId);
if (date == null){
return new AuthInfo("0001", "单号:", orderId, " 状态:待三级审批负责人 ", "王工");
}
//二级审批
if (authInt > 1000){
date = AuthService.queryAuthInfo("10002", orderId);
if (date == null){
return new AuthInfo("0001", "单号:", orderId, " 状态:待二级审批负责人 ", "张副总");
}
}
//一级审批
if (authInt > 10000){
date = AuthService.queryAuthInfo("10001", orderId);
if (date == null){
return new AuthInfo("0001", "单号:", orderId, " 状态:待一级审批负责人 ", "明总");
}
}
//审批完成
return new AuthInfo("0001", "单号:", orderId, " 状态:审批完成");
}
}
使用责任链模式
首先定义一个责任链表,所有的审批节点继承该类
public abstract class AuthLink {
protected String levelUserId; //级别人员id
protected String levelUserName; //级别人员名称
private AuthLink next; //下一级别人——责任链
public AuthLink(String levelUserId, String levelUserName) {
this.levelUserId = levelUserId;
this.levelUserName = levelUserName;
}
public AuthLink getNext(){
return next;
}
public AuthLink append(AuthLink next){
this.next = next;
return this;
}
public abstract AuthInfo doAuth(String uId,String orderId,int authInt);
}
三层审批节点
//三级领导审批
public class Level3Auth extends AuthLink {
public Level3Auth(String levelUserId, String levelUserName) {
super(levelUserId, levelUserName);
}
@Override
public AuthInfo doAuth(String uId, String orderId, int authInt) {
Date date = AuthService.queryAuthInfo("10003", orderId);
if (null == date){
return new AuthInfo("0001", "单号:", orderId, " 状态:待三级审批负责人 ", levelUserName);
}
AuthLink next = super.getNext();
if (null == next){
return new AuthInfo("0000", "单号:", orderId, " 状态:三级审批完成负责人", " 时间:", date.toString(), " 审批人:", levelUserName);
}
if (authInt <= 1000){
return new AuthInfo("0000", "单号:", orderId, " 状态:三级审批负责人完成", " 时间:", date.toString(), " 审批人:", levelUserName);
}
return next.doAuth(uId,orderId,authInt);
}
}
//二级领导审批
public class Level2Auth extends AuthLink {
public Level2Auth(String levelUserId, String levelUserName) {
super(levelUserId, levelUserName);
}
@Override
public AuthInfo doAuth(String uId, String orderId, int authInt) {
Date date = AuthService.queryAuthInfo("10002", orderId);
if (null == date){
return new AuthInfo("0001", "单号:", orderId, " 状态:待二级审批负责人 ", levelUserName);
}
AuthLink next = super.getNext();
if (null == next){
return new AuthInfo("0000", "单号:", orderId, " 状态:二级审批完成负责人", " 时间:", date.toString(), " 审批人:", levelUserName);
}
if (authInt > 1000 && authInt <= 10000){
return new AuthInfo("0000", "单号:", orderId, " 状态:二级审批完成负责人", " 时间:", date.toString(), " 审批人:", levelUserName);
}
return next.doAuth(uId,orderId,authInt);
}
}
//一级领导审批
public class Level1Auth extends AuthLink {
public Level1Auth(String levelUserId, String levelUserName) {
super(levelUserId, levelUserName);
}
@Override
public AuthInfo doAuth(String uId, String orderId, int authInt) {
Date date = AuthService.queryAuthInfo("10001", orderId);
if (null == date){
return new AuthInfo("0001", "单号:", orderId, " 状态:待一级审批负责人 ", levelUserName);
}
AuthLink next = super.getNext();
if (null == next){
return new AuthInfo("0000", "单号:", orderId, " 状态:一级审批完成负责人", " 时间:", date.toString(), " 审批人:", levelUserName);
}
return next.doAuth(uId,orderId,authInt);
}
}
测试
@SpringBootTest
@Slf4j
class Practice1602ApplicationTests {
@Test
void contextLoads() {
AuthLink authLink = new Level3Auth("10003","王工")
.append(new Level2Auth("10002","张副总")
.append(new Level1Auth("10001","明总")));
log.info(authLink.doAuth("yellowstar", "1300909091", 10001).toString());
log.info("模拟三级负责人审批");
AuthService.setAuthInfo("10003","1300909091");
log.info(authLink.doAuth("yellowstar", "1300909091", 10001).toString());
log.info("模拟二级负责人审批");
AuthService.setAuthInfo("10002","1300909091");
log.info(authLink.doAuth("yellowstar", "1300909091", 10001).toString());
log.info("模拟一级负责人审批");
AuthService.setAuthInfo("10001","1300909091");
log.info(authLink.doAuth("yellowstar", "1300909091", 10001).toString());
}
}
//结果
//AuthInfo(code=0001, info=单号:1300909091 状态:待三级审批负责人 王工)
//模拟三级负责人审批
//AuthInfo(code=0001, info=单号:1300909091 状态:待二级审批负责人 张副总)
//模拟二级负责人审批
//AuthInfo(code=0001, info=单号:1300909091 状态:待一级审批负责人 明总)
//模拟一级负责人审批
//AuthInfo(code=0000, info=单号:1300909091 状态:一级审批完成负责人 时间:Mon Jun 20 17:11:44 CST 2022 审批人:明总)
总结
责任链模式弱化了发出请求的人和处理请求的人之间的关系,如果不适用该模式,就必须有某个伟大的角色知道谁该处理当前请求,有点类似于中央集权制。
责任链模式很好的处理单一职责和开闭原则,简单了耦合也使对象关系更加清晰,而外部的调用方不需要关心责任链使如何进行处理的。但除了这些优点外也需要是适当的场景才进行使用,避免造成性能以及编排混乱调试测试疏漏问题。