本文转载自微信公众号《Java3y》,作者Java3y。转载本文请联系Java3y公众号。今天想和大家讨论一下如何去掉ifelse。已经工作过的人可能深有体会:没有什么是ifelse处理不了的,如果有,那就再嵌套一层。大部分人在做业务开发,ifelse是免不了的,但是如何让ifelse的逻辑看起来更顺眼,更漂亮,更容易维护呢?我想到了“责任链模型”。没错,责任链模型。当你在一个Service中看到很多ifelse逻辑时,你可能会想是否重构它,但是你还是做不到。所以,今天我想分享一个“通用”责任链模型的模板,把ifelse放进去就大功告成了。我相信你能学会。以前写设计模式文章的时候,有同学会评论说,我把事情搞复杂了,有简单的方法可以搞定,为什么要嵌套那么多层来搞这些花里胡哨的东西。在我看来,以最简单的方式来做并没有错。但是当代码量到了一定的时候,就多想想,换另外一个人来维护。能不能看懂,有没有更好的办法,这往往需要“抽象”的能力。这也是为什么那么多人推崇设计模式的原因。BB不多,加油。责任链的普遍实施现在我假设每个人都知道什么是责任链模式。如果你还不明白这一点,你可以先看看我之前的文章。首先我们会有一个业务执行器接口,所有的业务实现都会实现这个接口,也就是说上图中的逻辑A、B、C都会实现这个接口/***业务执行器*@author三失*/publicinterfaceBusinessProcess{voidprocess(ProcessContextcontext);}可以看到界面异常的简单,只有一个流程处理方法,方法接收ProcessContext。为什么process方法需要接收ProcessContext?这很简单。我们在处理逻辑A、B、C的时候,逻辑B可能需要依赖逻辑A的处理结果。所以我们需要一个载体来记录这些。因此,我们有ProcessContext,它代表责任链的上下文。/***ChainofResponsibilityContext*@author3y*/publicclassProcessContext{//codeprivateStringcode,标识责任链;//存储上下文的真正载体privateModelmodel;//标识断裂的责任链privateBooleanneedBreak=false;}now责任链的执行者和责任链涉及的上下文已经存在,也就是说我们已经有了责任链的主要抽象。下一步是我们需要把链串起来,所以我们需要一个模板。其实我们做的就是用一个List把BusinessProcess的子类串起来。/***业务执行模板(串责任链逻辑)*@author3y*/publicclassProcessTemplate{privateListprocessList;publicListgetProcessList(){returnprocessList;}publicvoidsetProcessList(ListprocessList){this.processList=processList;}}OK,现在我们已经抽象出了整个责任链,接下来就是暴露流程控制器来执行这个责任链:/***processcontrolleroftheresponsibility(theentirechainofresponsibilityGeneralcontrolofexecutionprocess)*@author3y*/@DatapublicclassProcessController{//不同的代码对应不同的责任链privateMaptemplateConfig=null;publicvoidprocess(ProcessContextcontext){//根据上下文的代码执行不同的职责链StringbusinessCode=context.getCode();ProcessTemplateprocessTemplate=templateConfig.get(businessCode);ListactionList=processTemplate.getProcessList();//遍历责任链的流程节点for(BusinessProcessaction:actionList){try{action.process(context);if(context.getNeedBreak()){break;}}catch(Exceptione2){//...}}}}可以看到会有一个Map用来存放多个模板责任链。这样做的好处是流程控制器ProcessController可以支持根据代码执行多个责任链。接下来就是我们有具体的BusinessProcess加入到ProcessTemplate链中,然后调用ProcessController方法执行整个push链。一般我们可以在XML中注入。比如现在我们有两个BusinessProcess的实现,分别是白名单和发送消息的逻辑:();if("3y".equals(user.getName())){context.setNeedBreak(true);}}}/***消息处理器*@author三歪*/@ServicepublicclassSendMessageProcessimplementsBusinessProcess{@Overridepublicvoidprocess(ProcessContextcontext){UserModeluser=(UserModel)context.getModel();System.out.println("Sendamessageto"+user.getName()+");}}然后我们将上面两个处理器添加到ProcessTemplate模板中,和将ProcessTemplate添加到ProcessControllerMap:
然后我们在接口中实现这个责任链:@RestControllerpublicclassUserController{@AutowiredprivateProcessControllerprocessController;@RequestMapping("/send")publicvoidsend(StringuserName){//构造上下文ProcessContextprocessContext=newProcessContext();UserModeluserModel=newUserModel();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("give"+userModel.getName()+"sendmessage");接下来我们来看看效果吧。从函数中我们可以发现,只要我们输入如果不是“3y”,那么就会打印消息上面的逻辑,其实就是一套通用责任链的代码。核心其实是四个角色:“业务抽象接口”、“执行时的上下文”、“业务实现类链”和“总控制器执行责任链”不理解的,三味推荐对比一下代码责任链的设计模式很好用,在项目中也有,很常见的就是把BusinessProcess/ProcessContext/ProcessTemplate/ProcessController的代码复制到自己的项目中,可以帮你摆脱掉原来的ifelse逻辑Pipeline不知道大家有没有看到Pipeline这个词,大家在学习Redis的时候可能已经看到了,在Redis中,我们会使用Pipeline来做批处理操作。宏观上看,Pipeline其实是一种架构思想,同时我也认为是“责任链模型”的一种实现方式,先来看看我的一个Pipeline实现的架构图side:可以看到前人实现的Pipeline比较复杂,上面的通用责任链模型不太好理解。经过分析,可以看出不是换药。的。下次你看到Pipeline这个词(因为这个词还是很常见的),你应该能想到责任链模型,然后你会发现你懂了。代码GitHub:https://github.com/ZhongFuCheng3y/Java3yTestRepositity