写点什么

代码优雅之道——如何干掉过多的 if else

作者:小小怪下士
  • 2023-04-25
    湖南
  • 本文字数:2919 字

    阅读完需:约 10 分钟

1、前言

注意标题是过多的,所以三四个就没必要干掉了。实际开发中我们经常遇到判断条件很多的情况,比如下图有 20 多种情况,不用想肯定是要优化代码的,需要思考的是如何去优化?



网上很多说用 switch case 啊,首先不比较 if else 与 switch case 效率问题的,只从代码整洁度来看二者没啥区别啊!我们这里更重要的是代码整洁度问题,为什么呢?来看下文的比较。

2、If else 与 switch case 效率真的差距很大么?

网上有两种见解:


第一种是说 switch…case 会生成一个跳转表来指示实际的 case 分支的地址,而这个跳转表的索引号与 switch 变量的值是相等的。从而,switch…case 不用像 if…else 那样遍历条件分支直到命中条件,而只需访问对应索引号的表项从而到达定位分支的目的。简单来说就是以空间换时间


第二种是说二者效率上差距并不大



于是我们自己去体验一下,不存在复杂业务逻辑,仅仅比较两种方式的效率:


    @Test    void contextLoads() {        testIf(100000);        System.gc();        testSwitch(100000);    }
private void testIf(Integer param) { long start = System.currentTimeMillis(); for (int i = 0; i < param; i++) { if (i == param-1){ System.out.println("if判断100000次"); } } long end = System.currentTimeMillis(); long total = end - start; System.out.println("Test消耗时间:" + total); }
private void testSwitch(Integer param){ long start = System.currentTimeMillis(); for (int i = 0; i < param; i++) { switch (i){ case 99999: System.out.println("switch判断100000次"); break; } } long end = System.currentTimeMillis(); long total = end - start; System.out.println("Test消耗时间:" + total); }
复制代码



可见差距并不大。而情况太多的时候谁还会去用 if else 和 switch case 呢?下面还是对两种方式的使用场景做简单的分析:


if else 能够把复杂的逻辑关系表达得清晰、易懂,包容了程序执行的各种情况。


switch 不适合业务系统的实际复杂需求,业务不断的变更迭代,一更改需求,条件的复杂度高了,switch 无力处理。switch 经常忘记写 break,估计很多人一不小心就忘记写了。switch…case 只能处理 case 为常量的情况。当情况不大于 5 种并且单一变量的值(如枚举),此时我们就可以使用 switch,它的可读性比 if 条件更清晰。


除了上述说到枚举的这种场景,建议使用 switch,其他个人愚见:只要情况不大于 5 种就直接使用 if else

3、策略+工厂模式

上述说到情况较少时并且业务逻辑不复杂的使用 if else 可以让代码清晰明了。当每种情况对应的业务逻辑复杂时,建议使用策略+工厂模式。这里我们举个栗子:厂家每个季度要举行不同的活动,我们使用策略工厂模式来实现


策略接口


public interface Strategy {
/** * 处理各种活动 * @return */ String dealActivity();}
复制代码


然后春夏秋冬四季活动类实现该接口



@Servicepublic class SpringActivity implements Strategy{    @Override    public String dealActivity() {        return "春季活动逻辑";    }}
复制代码


策略类工厂


public class StrategyFactory {    public static Strategy execute(Integer levelCode){        Strategy strategy = null;        switch (levelCode){            case 1:                strategy = new SpringActivity();                break;            case 2:                strategy = new SummerActivity();                break;            case 3:                strategy = new AutumnActivity();                break;            case 4:                strategy = new WinterActivity();                break;            default:                throw new IllegalArgumentException("活动编号错误");        }        return strategy;    }}
复制代码


然后在 service 层中传入对应的编码即可 ,我这里省略了 service


@RestControllerpublic class TestController {
@PostMapping("/dealActivity") public String dealActivity(Integer code){ Strategy strategy = StrategyFactory.execute(1); return strategy.dealActivity(); }}
复制代码



上述已经干掉了 if else ,后续季度活动调整去修改对应活动策略类中逻辑即可。缺点:如果情况比这多,那么策略类会越来越多,也就是所谓的策略类膨胀,并且没有****没有一个地方可以俯视整个业务逻辑。

4、Map+函数式接口

将上述策略类全部作为方法


@Servicepublic class ActivityStrategyService {
public String dealSpringActivity(){ return "春季活动逻辑"; }
public String dealSummerActivity() { return "夏季活动逻辑"; }
public String dealAutumnActivity() { return "秋季活动逻辑"; }
public String dealWinterActivity() { return "冬季活动逻辑"; }}复制代码
复制代码


再写个活动 Service


@Servicepublic class ActivityService {
@Autowired private ActivityStrategyService activityStrategyService;
@FunctionalInterface interface ActivityFunction<A>{ //这里可以传参啊,我这里举例用不上参数 //String dealActivity(A a); String dealActivity(); }
private final Map<Integer, ActivityFunction> strategyMap = new HashMap<>();
/** * 初始化策略 */ @PostConstruct public void initDispatcher(){ strategyMap.put(1,()->activityStrategyService.dealSpringActivity()); strategyMap.put(2, ()-> activityStrategyService.dealSummerActivity()); strategyMap.put(3, ()-> activityStrategyService.dealAutumnActivity()); strategyMap.put(4, ()-> activityStrategyService.dealWinterActivity()); }
public String dealActivity(Integer code){ ActivityFunction<Integer> function = strategyMap.get(code); //这里防止活动编号没匹配上,可以使用断言来判断从而抛出统一异常 return function.dealActivity(); }
}复制代码
复制代码


改变 Controller


@RestControllerpublic class TestController {
@Autowired private ActivityService activityService;
@PostMapping("/dealActivity") public String dealActivity(Integer code){// Strategy strategy = StrategyFactory.execute(1);// return strategy.dealActivity(); return activityService.dealActivity(code); }}
复制代码


作者:LoneWalker 链接:https://juejin.cn/post/7225056158981488699来源:稀土掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

用户头像

还未添加个人签名 2022-09-04 加入

热衷于分享java技术,一起交流学习,探讨技术。 需要Java相关资料的可以+v:xiaoyanya_1

评论

发布
暂无评论
代码优雅之道——如何干掉过多的if else_Java_小小怪下士_InfoQ写作社区