今天想来跟大家讨论一下怎么干掉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
这个词的时候(因为这个词还是很常见的),你们就应该能想到责任链模式
,然后你就发现你看懂了。