如何优雅的去掉if-else


前言

最近都在不停的CRUD,属实很难,想着自己的编码风格属实需要提高,同时也感觉自己应该尝试一下在写代码时,尝试一下使用新的方式来优化自己的代码

因为最近在做一个数据统计的需求,需要根据不同的类型去统计数据,因为有两个地方需要的是相同的数据,所以就想着把每个数据都写成一个方法,并且也是因为每个数据的统计规则不同,那么问题来了,核心数据统计直接每个方法都执行,然后取出数据就好了,但是统计图的显示就需要判断,获取的是哪个数据

2023121017272320231210172835

方案

if-else

最为常用的方式就是if-else了,这种方式也有优点就是简单易读,if-else可谓是从我们刚开始学习编程就开始接触,这也是所有判断最简单,最常用的,可读性也是很强的,缺点就是看起来不太高级并且会让代码看起来很“冗余”,这种方式只需要每次判断一下请求的类型,然后进行相应的处理就行了

策略模式

抽象一个策略接口


public interface TaskStrategy {

    String getMode();
    void doAction();
}

然后使用一个统一的入口来管理策略,taskStrategyList这里就是存放的所有实现了策略接口的具体策略,我们,使用@Autowired将所有的具体策略注入到集合中


@Component
public class TaskContext {

    private final Map<String, TaskStrategy> strategyMap = new ConcurrentHashMap<>();


    @Autowired
    public TaskContext(List<TaskStrategy> taskStrategyList){
        for (TaskStrategy taskStrategy : taskStrategyList) {
            strategyMap.put(taskStrategy.getMode(),taskStrategy);
        }
    }

    public void executeStrategy(String mode){
        TaskStrategy strategy = this.strategyMap.get(mode);
        if (strategy == null){
            throw new RuntimeException("策略为空");
        }
        strategy.doAction();
    }
}

然后在具体需要使用策略的地方来进行调用对应的策略就可以了,这里可以使用HashMap来搭配使用


 private static Map<String, Method> methodMap = new HashMap<>();

    @Override
    public void afterPropertiesSet() throws Exception {
        methodMap = initializeMethodMap();
    }

    public Map<String, Method> getMethodMap() {
        return methodMap;
    }

    private Map<String, Method> initializeMethodMap() {
        Map<String, Method> map = new HashMap<>();
        try {
            map.put("MODE", new TaskStrategyService());
            ...
            ... 
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return map;
    }

根据传入的mode类型来获取对应的方法就行了

Map+反射

Map+反射,也是我最后采用的方式,因为接口里面的内容并不复杂,懒得为了实现策略模式而新建及格类,所以就是直接为每个接口的实现单独抽象了方法,然后维护了一张方法的执行表就行了

这里需要注意,afterPropertiesSet()需要方法实现InitializingBean接口,因为我是在实现类中操作的,所以我需要在接口注入时,初始化表的数据


    private static Map<String, Method> methodMap = new HashMap<>();

    @Override
    public void afterPropertiesSet() throws Exception {
        methodMap = initializeMethodMap();
    }

    public Map<String, Method> getMethodMap() {
        return methodMap;
    }

    private Map<String, Method> initializeMethodMap() {
        Map<String, Method> map = new HashMap<>();
        try {
            map.put("amountTotal", this.getClass().getMethod("getAmountTotal", Long.class, Date.class, Date.class, Integer.class));
            map.put("ordersTotal", this.getClass().getMethod("getOrdersTotal", Long.class, Date.class, Date.class, Integer.class));
            map.put("buyerTotal", this.getClass().getMethod("getBuyerTotal", Long.class, Date.class, Date.class, Integer.class));
            map.put("forceTax", this.getClass().getMethod("getForceTax", Long.class, Date.class, Date.class, Integer.class));
            map.put("visitUsers", this.getClass().getMethod("getVisitUsers", Long.class, Date.class, Date.class, Integer.class));
            map.put("visitTotal", this.getClass().getMethod("getVisitTotal", Long.class, Date.class, Date.class, Integer.class));
            map.put("newBuyerTotal", this.getClass().getMethod("getNewBuyerTotal", Long.class, Date.class, Date.class, Integer.class));
            map.put("refundAmount", this.getClass().getMethod("getRefundAmount", Long.class, Date.class, Date.class, Integer.class));
            map.put("newMemberTotal", this.getClass().getMethod("getNewMemberTotal", Long.class, Date.class, Date.class, Integer.class));
            map.put("newSaleTotal", this.getClass().getMethod("getNewSaleTotal", Long.class, Date.class, Date.class, Integer.class));
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return map;
    }


然后根据前端传入的查询类型来表中查询出对应的方法,并且使用反射来执行就可以了


Method method = getMethodMap().get(vo.getDataType());
String value = method.invoke(this,mbrId,startTime,_endTime,vo.getType()).toString();

总结

emmmmmm...我自己平常使用的就是这三种,当然肯定不止这几种方式,其实核心都是一样的,需要一个地方来判断需要具体执行哪部分代码,然后执行就行。

还看到有使用函数式接口来实现,过两天补上剩下的几种方法

Loading...