三歪手把手教你干掉if else
本文轉載自微信公眾號「Java3y」,作者Java3y。轉載本文請聯系Java3y公眾號。
今天想來跟大家討論一下怎么干掉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這個詞的時候(因為這個詞還是很常見的),你們就應該能想到責任鏈模式,然后你就發現你看懂了。
代碼GitHub:https://github.com/ZhongFuCheng3y/Java3yTestReposity