当前位置:网站首页>手把手教你干掉if else
手把手教你干掉if else
2022-08-02 20:52:00 【马小屑】
今天想来跟大家讨论一下怎么干掉if else。
已经工作的人可能深有体会:没有什么是if else搞不掂的,如果有,那就再嵌套一层。
大多数人都是做业务开发的,if else是避免不了的,但怎么让if else的逻辑看起来更顺眼,变得更加好看,更加好维护呢?
如果之前看过三歪文章的同学可能就会想到「责任链模式」。
没错就是责任链模式
当你看到一个Service中有一大堆if else 逻辑的时候,可能你会幻想着要不要重构掉,但是始终下不了手。
所以,今天想来分享一个「通用」的责任链模式的模板,把if else给套进去就完事了,我相信都能学会。
之前写设计模式文章的时候,有的同学会评论说我把东西搞复杂了,本来就有简单的方式去弄,为啥就要嵌套这么多层去搞这些花里胡哨的东西。
在我看来,用最简单的方式去实现是没有任何问题的。但达到一定代码量的时候,多想想一下,换一个人去维护,人家能不能看懂,有没有更加好的方式,这往往就需要「抽象」的能力。
这也是为什么这么多人推崇设计模式的原因。
不多BB,来吧。
责任链通用实现
现在我就默认大家都知道什么是责任链模式了,如果还对这个不懂的同学,可以先看看我之前的文章。

首先,我们会有一个业务执行器接口,所有的业务实现都会实现该接口,这意味着上图的逻辑A、B、C都会实现这个接口
/**
* 业务执行器
* @author 三歪
*/
public interface BusinessProcess {
void process(ProcessContext context);
}
可以看到的是接口异常的简单,只有一个process处理的方法,方法接收的是ProcessContext
为什么process方法需要接收ProcessContext?很简单,我们在处理逻辑A、B、C的时候,可能逻辑B需要依赖逻辑A的处理结果。于是我们就需要有一个载体把这些给记录下来。
所以,我们就有了ProcessContext,它代表的是责任链的上下文。
/**
* 责任链上下文
* @author 3y
*/
public class ProcessContext {
// 标识责任链的code
private String code;
// 存储上下文的真正载体
private Model model;
// 责任链中断的标识
private Boolean needBreak = false;
}
现在责任链的执行器和责任链所涉及的上下文都已经有了,这意味着我们已经有了责任链最主要的抽象了。
接下来就是我们需要把链给串起来,于是我们需要一个模板,其实我们做的就是用一个List来把BusinessProcess的子类给串起来。
/**
* 业务执行模板(把责任链的逻辑串起来)
* @author 3y
*/
public class ProcessTemplate {
private List<BusinessProcess> processList;
public List<BusinessProcess> getProcessList() {
return processList;
}
public void setProcessList(List<BusinessProcess> processList) {
this.processList = processList;
}
}
OK,现在我们已经把责任链的整块给抽象好了,接下来就是暴露流程控制器去执行这个责任链:
/**
* 责任链的流程控制器(整个责任链的执行流程通用控制)
* @author 3y
*/
@Data
public class ProcessController {
// 不同的code 对应不同的责任链
private Map<String, ProcessTemplate> templateConfig = null;
public void process(ProcessContext context) {
//根据上下文的Code 执行不同的责任链
String businessCode = context.getCode();
ProcessTemplate processTemplate = templateConfig.get(businessCode);
List<BusinessProcess> actionList = processTemplate.getProcessList();
//遍历某个责任链的流程节点
for (BusinessProcess action : actionList) {
try {
action.process(context);
if (context.getNeedBreak()) {
break;
}
} catch (Exception e2) {
//...
}
}
}
}
我们可以看到的是在ProcessController执行链通用的流程控制器上会有一个Map去存储多个责任链的模板,这样做的好处就是:ProcessController这个流程控制器可以根据code支持多个责任链执行。
接下来就是我们有具体的BusinessProcess去加入到ProcessTemplate的链上,然后调用ProcessController的方法去执行整一条推送链。
一般我们在XML注入就好了,比如说现在我们有两个BusinessProcess的实现,分别是白名单和发消息的逻辑:
/**
* 白名单处理器
* @author 3y
*/
@Service
public class WhiteListProcess implements BusinessProcess {
@Override
public void process(ProcessContext context) {
UserModel user = (UserModel) context.getModel();
if ("3y".equals(user.getName())) {
context.setNeedBreak(true);
}
}
}
/**
* 发消息处理器
* @author 三歪
*/
@Service
public class SendMessageProcess implements BusinessProcess {
@Override
public void process(ProcessContext context) {
UserModel user = (UserModel) context.getModel();
System.out.println("给"+user.getName()+"发消息");
}
}
然后我们把上面两个处理器添加到ProcessTemplate的模板上,把ProcessTemplate添加到ProcessController的Map上:
<!--发送消息的责任链-->
<bean id="sendMessageTemplate" class="com.chainofresponsibility.ProcessTemplate">
<property name="processList">
<list>
<ref bean="whiteListProcess"></ref>
<ref bean="sendMessageProcess"></ref>
</list>
</property>
</bean>
<!--通用流程处理器,维护多条责任链-->
<bean id="processController" class="com.chainofresponsibility.ProcessController">
<property name="templateConfig">
<map>
<entry key="sendMessage" value-ref="sendMessageTemplate" />
</map>
</property>
</bean>
然后我们在接口里边执行这个责任链:
@RestController
public class UserController {
@Autowired
private ProcessController processController;
@RequestMapping("/send")
public void send(String userName) {
// 构建上下文
ProcessContext processContext = new ProcessContext();
UserModel userModel = new UserModel();
userModel.setAge("24");
userModel.setName(userName);
processContext.setModel(userModel);
processContext.setCode("sendMessage");
processController.process(processContext);
}
}
我做了这么大的一套东西实现了什么功能?其实就一个if逻辑:
if ("3y".equals(userModel.getName())) {
return;
}
System.out.println("给" + userModel.getName() + "发消息");
下面我们还是来看看效果,从功能上我们可以发现,只要我们输入的不是「3y」,那就会打印消息

上面的逻辑,实际上就是一套通用的责任链的代码,最核心的其实就是四个角色:「业务抽象接口」、「执行过程中的上下文」、「将业务实现类串起来」和「一个通用的控制器执行责任链」

如果没看懂的同学,三歪建议再对比一下代码看看,责任链这种设计模式是非常好用,在项目里边也是非常常见的。
只要把BusinessProcess/ProcessContext/ProcessTemplate/ProcessController的代码给拷过去自己的项目中,这就能帮你把原有的if else逻辑给干掉。
Pipeline
不知道大家看过Pipeline这个词了没,在学Redis的时候可能会见过,在Redis里边我们会用Pipeline去做批量的操作。
抛开Redis的Pipeline,但从宏观的角度上来,Pipeline其实是一种架构思想。
同时我也认为它是「责任链模式」的实现之一。
下面来看看我这边的一个Pipeline实现的架构图:

可以看到前人实现的Pipepline还是相对复杂的,没有上面通用的责任链模式好理解,经过分析可以看到都是换汤不换药的。
下次再见到Pipeline这个词的时候(因为这个词还是很常见的),你们就应该能想到责任链模式,然后你就发现你看懂了。
边栏推荐
猜你喜欢

go——内存分配机制

PyRosetta 安装方法之Conda安装

奥特学园ROS笔记--7(289-325节)

千人优学 | GBase 8s数据库2022年6月大学生专场实训圆满结束

JMeter的基本使用

Day12 接口和协议

Tencent YunMeng every jie: I experienced by cloud native authors efficiency best practices case

The software testing process specification is what?Specific what to do?
VisualStudio 制作Dynamic Link Library动态链接库文件

Use the TCP protocol, we won't lost package?
随机推荐
包管理工具Chocolate - Win10如何安装Chocolate工具、快速上手、进阶用法
Informatics Olympiad All-in-One (1260: [Example 9.4] Intercepting Missiles (Noip1999))
PLC working principle animation
[C题目]力扣141. 环形链表
ACE JET NPOI
框架设计:PC 端单页多页框架如何设计与落地
ICLR 2022最佳论文:基于对比消歧的偏标签学习
C语言中变量在内存中的保存与访问
Li Mu hands-on deep learning V2-BERT pre-training and code implementation
【C语言进阶】--指针典题剖析
How to quickly compare two byte arrays for equality in .NET
go——内存分配机制
主成分分析(PCA)
[C题目]力扣142. 环形链表 II
「每周译Go」这次我们来点不一样的!--《How to Code in Go》系列上线
包管理工具npm- node package management相关知识 、检查包更新、NPM包上传、更换镜像、npm ERR! registry error parsing json
用了TCP协议,就一定不会丢包吗?
Mysql用户管理
【21天学习挑战赛】冒泡排序与插入排序
vscode如何能将输出从OUTPUT改为TERMINAL或者DebugConsole