三歪手把手教你干掉if else

开发 前端
今天想来跟大家讨论一下怎么干掉if else。已经工作的人可能深有体会:没有什么是if else搞不掂的,如果有,那就再嵌套一层。

 [[332944]]

本文转载自微信公众号「Java3y」,作者Java3y。转载本文请联系Java3y公众号。

今天想来跟大家讨论一下怎么干掉if else。

已经工作的人可能深有体会:没有什么是if else搞不掂的,如果有,那就再嵌套一层。

大多数人都是做业务开发的,if else是避免不了的,但怎么让if else的逻辑看起来更顺眼,变得更加好看,更加好维护呢?

如果之前看过三歪文章的同学可能就会想到「责任链模式」。

没错就是 责任链模式

当你看到一个Service中有一大堆if else 逻辑的时候,可能你会幻想着要不要重构掉,但是始终下不了手。

所以,今天想来分享一个「通用」的责任链模式的模板,把if else给套进去就完事了,我相信都能学会。

之前写设计模式文章的时候,有的同学会评论说我把东西搞复杂了,本来就有简单的方式去弄,为啥就要嵌套这么多层去搞这些花里胡哨的东西。

在我看来,用最简单的方式去实现是没有任何问题的。但达到一定代码量的时候,多想想一下,换一个人去维护,人家能不能看懂,有没有更加好的方式,这往往就需要「抽象」的能力。

这也是为什么这么多人推崇设计模式的原因。

不多BB,来吧。

责任链通用实现

现在我就默认大家都知道什么是责任链模式了,如果还对这个不懂的同学,可以先看看我之前的文章。

 

首先,我们会有一个业务执行器接口,所有的业务实现都会实现该接口,这意味着上图的逻辑A、B、C都会实现这个接口

  1. /** 
  2.  * 业务执行器 
  3.  * @author 三歪 
  4.  */ 
  5. public interface BusinessProcess { 
  6.     void process(ProcessContext context); 

可以看到的是接口异常的简单,只有一个process处理的方法,方法接收的是ProcessContext

为什么process方法需要接收ProcessContext?很简单,我们在处理逻辑A、B、C的时候,可能逻辑B需要依赖逻辑A的处理结果。于是我们就需要有一个载体把这些给记录下来。

所以,我们就有了ProcessContext,它代表的是责任链的上下文。

  1. /** 
  2.  * 责任链上下文 
  3.  * @author 3y 
  4.  */ 
  5. public class ProcessContext { 
  6.     // 标识责任链的code 
  7.     private String code; 
  8.     // 存储上下文的真正载体 
  9.     private Model model; 
  10.     // 责任链中断的标识 
  11.     private Boolean needBreak = false

现在责任链的执行器和责任链所涉及的上下文都已经有了,这意味着我们已经有了责任链最主要的抽象了。

接下来就是我们需要把链给串起来,于是我们需要一个模板,其实我们做的就是用一个List来把BusinessProcess的子类给串起来。

  1. /** 
  2.  * 业务执行模板(把责任链的逻辑串起来) 
  3.  * @author 3y 
  4.  */ 
  5. public class ProcessTemplate { 
  6.     private List<BusinessProcess> processList; 
  7.     public List<BusinessProcess> getProcessList() { 
  8.         return processList; 
  9.     } 
  10.     public void setProcessList(List<BusinessProcess> processList) { 
  11.         this.processList = processList; 
  12.     } 

OK,现在我们已经把责任链的整块给抽象好了,接下来就是暴露流程控制器去执行这个责任链:

  1. /** 
  2.  * 责任链的流程控制器(整个责任链的执行流程通用控制) 
  3.  * @author 3y  
  4.  */ 
  5. @Data 
  6. public class ProcessController { 
  7.      
  8.     // 不同的code 对应不同的责任链 
  9.     private Map<String, ProcessTemplate> templateConfig = null
  10.  
  11.     public void process(ProcessContext context) { 
  12.         //根据上下文的Code 执行不同的责任链 
  13.         String businessCode = context.getCode(); 
  14.         ProcessTemplate processTemplate = templateConfig.get(businessCode); 
  15.         List<BusinessProcess> actionList = processTemplate.getProcessList(); 
  16.         //遍历某个责任链的流程节点 
  17.         for (BusinessProcess action : actionList) { 
  18.             try { 
  19.                 action.process(context); 
  20.                 if (context.getNeedBreak()) { 
  21.                     break; 
  22.                 } 
  23.             } catch (Exception e2) { 
  24.                 //... 
  25.             } 
  26.         } 
  27.     } 

我们可以看到的是在ProcessController执行链通用的流程控制器上会有一个Map去存储多个责任链的模板,这样做的好处就是:ProcessController这个流程控制器可以根据code支持多个责任链执行。

接下来就是我们有具体的BusinessProcess去加入到ProcessTemplate的链上,然后调用ProcessController的方法去执行整一条推送链。

一般我们在XML注入就好了,比如说现在我们有两个BusinessProcess的实现,分别是白名单和发消息的逻辑:

  1. /** 
  2.  * 白名单处理器 
  3.  * @author 3y 
  4.  */ 
  5. @Service 
  6. public class WhiteListProcess implements BusinessProcess { 
  7.     @Override 
  8.     public void process(ProcessContext context) { 
  9.         UserModel user = (UserModel) context.getModel(); 
  10.         if ("3y".equals(user.getName())) { 
  11.             context.setNeedBreak(true); 
  12.         } 
  13.     } 
  14.  
  15. /** 
  16.  * 发消息处理器 
  17.  * @author 三歪 
  18.  */ 
  19. @Service 
  20. public class SendMessageProcess implements BusinessProcess { 
  21.  
  22.     @Override 
  23.     public void process(ProcessContext context) { 
  24.         UserModel user = (UserModel) context.getModel(); 
  25.         System.out.println("给"+user.getName()+"发消息"); 
  26.     } 

然后我们把上面两个处理器添加到ProcessTemplate的模板上,把ProcessTemplate添加到ProcessController的Map上:

  1. <!--发送消息的责任链--> 
  2. <bean id="sendMessageTemplate" class="com.chainofresponsibility.ProcessTemplate"
  3.   <property name="processList"
  4.     <list> 
  5.       <ref bean="whiteListProcess"></ref> 
  6.       <ref bean="sendMessageProcess"></ref> 
  7.     </list> 
  8.   </property> 
  9. </bean> 
  10.  
  11. <!--通用流程处理器,维护多条责任链--> 
  12. <bean id="processController" class="com.chainofresponsibility.ProcessController"
  13.   <property name="templateConfig"
  14.     <map> 
  15.       <entry key="sendMessage" value-ref="sendMessageTemplate" /> 
  16.     </map> 
  17.   </property> 
  18. </bean> 

然后我们在接口里边执行这个责任链:

  1. @RestController 
  2. public class UserController { 
  3.     @Autowired 
  4.     private ProcessController processController; 
  5.  
  6.     @RequestMapping("/send"
  7.     public void  send(String userName) { 
  8.         // 构建上下文 
  9.         ProcessContext processContext = new ProcessContext(); 
  10.  
  11.         UserModel userModel = new UserModel(); 
  12.         userModel.setAge("24"); 
  13.         userModel.setName(userName); 
  14.         processContext.setModel(userModel); 
  15.  
  16.         processContext.setCode("sendMessage"); 
  17.  
  18.         processController.process(processContext); 
  19.     } 

我做了这么大的一套东西实现了什么功能?其实就一个if逻辑:

  1. if ("3y".equals(userModel.getName())) { 
  2.   return
  3. System.out.println("给" + userModel.getName() + "发消息"); 

下面我们还是来看看效果,从功能上我们可以发现,只要我们输入的不是「3y」,那就会打印消息

 

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

 

如果没看懂的同学,三歪建议再对比一下代码看看,责任链这种设计模式是非常好用,在项目里边也是非常常见的。

只要把BusinessProcess/ProcessContext/ProcessTemplate/ProcessController的代码给拷过去自己的项目中,这就能帮你把原有的if else逻辑给干掉。

Pipeline

不知道大家看过Pipeline这个词了没,在学Redis的时候可能会见过,在Redis里边我们会用Pipeline去做批量的操作。

抛开Redis的Pipeline,但从宏观的角度上来,Pipeline其实是一种架构思想。

同时我也认为它是「责任链模式」的实现之一。

下面来看看我这边的一个Pipeline实现的架构图:

 

可以看到前人实现的Pipepline还是相对复杂的,没有上面通用的责任链模式好理解,经过分析可以看到都是换汤不换药的。

下次再见到Pipeline这个词的时候(因为这个词还是很常见的),你们就应该能想到责任链模式,然后你就发现你看懂了。

代码GitHub:https://github.com/ZhongFuCheng3y/Java3yTestReposity

 

责任编辑:武晓燕 来源: Java3y
相关推荐

2021-07-14 09:00:00

JavaFX开发应用

2011-01-10 14:41:26

2011-05-03 15:59:00

黑盒打印机

2023-04-26 12:46:43

DockerSpringKubernetes

2022-03-14 14:47:21

HarmonyOS操作系统鸿蒙

2022-01-08 20:04:20

拦截系统调用

2022-07-27 08:16:22

搜索引擎Lucene

2022-12-07 08:42:35

2021-02-26 11:54:38

MyBatis 插件接口

2011-02-22 13:46:27

微软SQL.NET

2021-12-28 08:38:26

Linux 中断唤醒系统Linux 系统

2017-10-20 13:41:11

Spark集群代码

2010-09-16 14:08:13

无线双网

2020-08-12 07:41:39

SQL 优化语句

2017-07-07 11:01:04

Spark性能调优

2021-09-18 14:26:49

Linux Linux 启动流程Linux 系统

2024-03-05 18:27:43

2021-08-02 07:35:19

Nacos配置中心namespace

2021-07-01 09:31:50

MySQL SQL 语句数据库

2011-04-28 15:09:15

jQueryjqPlot
点赞
收藏

51CTO技术栈公众号