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

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();
}

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

@Service
public 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

@RestController
public class TestController {

    @PostMapping("/dealActivity")
    public String dealActivity(Integer code){
        Strategy strategy = StrategyFactory.execute(1);
        return strategy.dealActivity();
    }
}

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

4、Map+函数式接口

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

@Service
public class ActivityStrategyService {

    public String dealSpringActivity(){
        return "春季活动逻辑";
    }

    public String dealSummerActivity() {
        return "夏季活动逻辑";
    }

    public String dealAutumnActivity() {
        return "秋季活动逻辑";
    }

    public String dealWinterActivity() {
        return "冬季活动逻辑";
    }
}

再写个活动Service

@Service
public 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

@RestController
public 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);
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容