概述
我们这里来说因多种状态引起的多个分支判断条件的代码的优化。
工程中有段代码如下:
可以看到,分支条件已经到了9个,在Service层直接调用了持久层(Mybatis)提供的接口,也还算清晰。不过代码量太大,增加个状态就要修改这个类,难以维护。 那么我们该如何优化呢? 核心思想:使用多态代替判断条件
为了更加清晰,下面新建个单独的工程来演示下,并逐步优化
原工程缩影
越简单 越直观 ,工程如下:
Domain对象
package com.artisan.optimization.ifelse; public class FlowInfo { private Integer currentState; // 其他字段省略.... public Integer getCurrentState() { return currentState; } public void setCurrentState(Integer currentState) { this.currentState = currentState; } }
持久层
package com.artisan.optimization.ifelse; import java.util.ArrayList; import java.util.List; public class FlowInfoDao { List<FlowInfo> flowInfoList = new ArrayList<>(); public List<FlowInfo> getWorkDraftList(FlowInfo flowInfo) { System.out.println("draft...."); return flowInfoList; } public List<FlowInfo> getWorkTodoList(FlowInfo flowInfo) { System.out.println("todo...."); return flowInfoList; } public List<FlowInfo> getWorkFinishList(FlowInfo flowInfo) { System.out.println("finish...."); return null; } public List<FlowInfo> getWorkRejectList(FlowInfo flowInfo) { System.out.println("reject...."); return null; } }
Service层
package com.artisan.optimization.ifelse; import java.util.List; public class FlowInfoService { FlowInfoDao flowDao = new FlowInfoDao(); public List<FlowInfo> getWorkFlowList(final FlowInfo flowInfo) { // 0:草稿 if (0 == flowInfo.getCurrentState()) { return flowDao.getWorkDraftList(flowInfo); } // 1:待办 if (1 == flowInfo.getCurrentState()) { return flowDao.getWorkTodoList(flowInfo); } // 2:完成 if (2 == flowInfo.getCurrentState()) { return flowDao.getWorkFinishList(flowInfo); } // 3:驳回 if (3 == flowInfo.getCurrentState()) { return flowDao.getWorkRejectList(flowInfo); } return null; } }
模拟的原始代码如上, 这里我们暂定有4个状态,假设有很多个,难以维护。
分析下上面的代码在不同判断条件下,执行的业务逻辑是不同的,那么我们可以把这种执行逻辑抽象出来,用多态的形式来定义不同的执行方式。
测试
package com.artisan.optimization.ifelse; public class Main { public static void main(String[] args) { FlowInfoService flowInfoService = new FlowInfoService(); FlowInfo flowInfo = new FlowInfo(); flowInfo.setCurrentState(0); flowInfoService.getWorkFlowList(flowInfo); flowInfo.setCurrentState(1); flowInfoService.getWorkFlowList(flowInfo); flowInfo.setCurrentState(2); flowInfoService.getWorkFlowList(flowInfo); flowInfo.setCurrentState(3); flowInfoService.getWorkFlowList(flowInfo); } }
第一次优化 【使用多态代替判断条件】
既然有了上面的分析:
分析下上面的代码在不同判断条件下,执行的业务逻辑是不同的,那么我们可以把这种执行逻辑抽象出来,用多态的形式来定义不同的执行方式。
来,操刀吧
Step1: 定义一个抽象的父类 AbstractFlowInfoExecutor ,抽取公共属性和方法
package com.artisan.optimization.ifelse.executor; import java.util.List; import com.artisan.optimization.ifelse.FlowInfo; import com.artisan.optimization.ifelse.FlowInfoDao; public abstract class AbstractFlowInfoExecutor { // 公共属性,提取到抽象类中,子类直接使用即可 FlowInfoDao flowDao = new FlowInfoDao(); // 子类可重写该方法 public List<FlowInfo> process(FlowInfo flowInfo) { return null; } }
Step2: 子类重写父类的方法,实现自定义业务逻辑
完成了抽象父类的定义后,就可以把代码块中不同条件下的方法抽到各个不同的具体类里面去了,如下
flowInfo.getCurrentState() == 0 分支
package com.artisan.optimization.ifelse.executor; import java.util.List; import com.artisan.optimization.ifelse.FlowInfo; public class DraftExecutor extends AbstractFlowInfoExecutor { @Override public List<FlowInfo> process(FlowInfo flowInfo) { return flowDao.getWorkDraftList(flowInfo); } }
flowInfo.getCurrentState() == 1 分支
package com.artisan.optimization.ifelse.executor; import java.util.List; import com.artisan.optimization.ifelse.FlowInfo; public class TodoExecutor extends AbstractFlowInfoExecutor { @Override public List<FlowInfo> process(FlowInfo flowInfo) { return flowDao.getWorkTodoList(flowInfo); } }
flowInfo.getCurrentState() == 2 分支
package com.artisan.optimization.ifelse.executor; import java.util.List; import com.artisan.optimization.ifelse.FlowInfo; public class FinishExecutor extends AbstractFlowInfoExecutor { @Override public List<FlowInfo> process(FlowInfo flowInfo) { return flowDao.getWorkFinishList(flowInfo); } }
flowInfo.getCurrentState() == 3 分支
package com.artisan.optimization.ifelse.executor; import java.util.List; import com.artisan.optimization.ifelse.FlowInfo; public class RejectExecutor extends AbstractFlowInfoExecutor { @Override public List<FlowInfo> process(FlowInfo flowInfo) { return flowDao.getWorkRejectList(flowInfo); } }
Step3: 改造Service层
package com.artisan.optimization.ifelse; import java.util.List; import com.artisan.optimization.ifelse.executor.AbstractFlowInfoExecutor; import com.artisan.optimization.ifelse.executor.DraftExecutor; import com.artisan.optimization.ifelse.executor.FinishExecutor; import com.artisan.optimization.ifelse.executor.RejectExecutor; import com.artisan.optimization.ifelse.executor.TodoExecutor; public class FlowInfoService { public List<FlowInfo> getWorkFlowList(final FlowInfo flowInfo) { AbstractFlowInfoExecutor executor = null; // 根据状态实例化不同的executor // 0:草稿 if (0 == flowInfo.getCurrentState()) { executor = new DraftExecutor(); } // 1:待办 if (1 == flowInfo.getCurrentState()) { executor = new TodoExecutor(); } // 2:完成 if (2 == flowInfo.getCurrentState()) { executor = new FinishExecutor(); } // 3:驳回 if (3 == flowInfo.getCurrentState()) { executor = new RejectExecutor(); } // 执行 return executor.process(flowInfo); } }
Step3: 测试下
第二次优化【工厂模式】
经过上一轮的优化后,虽然把业务逻辑抽取到单独的子类中了,但Service层依然还是存在分支条件
那继续优化吧
Step1:使用工厂模式,定义一个工厂类来生成不用的子类Executor
package com.artisan.optimization.ifelse.factory; import com.artisan.optimization.ifelse.FlowInfo; import com.artisan.optimization.ifelse.executor.AbstractFlowInfoExecutor; import com.artisan.optimization.ifelse.executor.DraftExecutor; import com.artisan.optimization.ifelse.executor.FinishExecutor; import com.artisan.optimization.ifelse.executor.RejectExecutor; import com.artisan.optimization.ifelse.executor.TodoExecutor; public class FlowInfoExecutorFactory { public static AbstractFlowInfoExecutor executor(FlowInfo flowInfo) { // if (0 == flowInfo.getCurrentState()) { return new DraftExecutor(); } // 1:待办 if (1 == flowInfo.getCurrentState()) { return new TodoExecutor(); } // 2:完成 if (2 == flowInfo.getCurrentState()) { return new FinishExecutor(); } // 3:驳回 if (3 == flowInfo.getCurrentState()) { return new RejectExecutor(); } return null; } }
Step2: Service层继续改造
package com.artisan.optimization.ifelse; import java.util.List; import com.artisan.optimization.ifelse.executor.AbstractFlowInfoExecutor; import com.artisan.optimization.ifelse.factory.FlowInfoExecutorFactory; public class FlowInfoService { public List<FlowInfo> getWorkFlowList(final FlowInfo flowInfo) { // 工厂 AbstractFlowInfoExecutor executor = FlowInfoExecutorFactory.executor(flowInfo); return executor.process(flowInfo); } }
2行,搞定!
Step3: 测试下
当然了,工厂中状态和Executor的映射关系可以使用Map来维护
结果:
Enum也是可以的
结果:
小结
经过**多态和工厂模式**的改造后,只需要两行就可以了。 各个子类Executor和Service层的耦合已经很低了,如果有新的状态,只需要修改工厂类和增加子Executor即可。