代碼優(yōu)雅之道——如何干掉過多的if else

1、前言

注意標題是過多的,所以三四個就沒必要干掉了。實際開發(fā)中我們經(jīng)常遇到判斷條件很多的情況,比如下圖有20多種情況,不用想肯定是要優(yōu)化代碼的,需要思考的是如何去優(yōu)化?

網(wǎng)上很多說用switch case啊,首先不比較if else與switch case效率問題的,只從代碼整潔度來看二者沒啥區(qū)別啊!我們這里更重要的是代碼整潔度問題,為什么呢?來看下文的比較。

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

網(wǎng)上有兩種見解:

第一種是說switch…case會生成一個跳轉(zhuǎn)表來指示實際的case分支的地址,而這個跳轉(zhuǎn)表的索引號與switch變量的值是相等的。從而,switch…case不用像if…else那樣遍歷條件分支直到命中條件,而只需訪問對應(yīng)索引號的表項從而到達定位分支的目的。簡單來說就是以空間換時間

第二種是說二者效率上差距并不大

于是我們自己去體驗一下,不存在復(fù)雜業(yè)務(wù)邏輯,僅僅比較兩種方式的效率:

    @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能夠把復(fù)雜的邏輯關(guān)系表達得清晰、易懂,包容了程序執(zhí)行的各種情況。

switch不適合業(yè)務(wù)系統(tǒng)的實際復(fù)雜需求,業(yè)務(wù)不斷的變更迭代,一更改需求,條件的復(fù)雜度高了,switch無力處理。switch經(jīng)常忘記寫break,估計很多人一不小心就忘記寫了。switch…case只能處理case為常量的情況。當情況不大于5種并且單一變量的值(如枚舉),此時我們就可以使用switch,它的可讀性比if條件更清晰。

除了上述說到枚舉的這種場景,建議使用switch,其他個人愚見:只要情況不大于5種就直接使用if else

3、策略+工廠模式

上述說到情況較少時并且業(yè)務(wù)邏輯不復(fù)雜的使用if else可以讓代碼清晰明了。當每種情況對應(yīng)的業(yè)務(wù)邏輯復(fù)雜時,建議使用策略+工廠模式。這里我們舉個栗子:廠家每個季度要舉行不同的活動,我們使用策略工廠模式來實現(xiàn)

策略接口

public interface Strategy {

    /**
     * 處理各種活動
     * @return
     */
    String dealActivity();
}

然后春夏秋冬四季活動類實現(xiàn)該接口

@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層中傳入對應(yīng)的編碼即可 ,我這里省略了service

@RestController
public class TestController {

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

上述已經(jīng)干掉了if else ,后續(xù)季度活動調(diào)整去修改對應(yīng)活動策略類中邏輯即可。缺點:如果情況比這多,那么策略類會越來越多,也就是所謂的策略類膨脹,并且沒有****沒有一個地方可以俯視整個業(yè)務(wù)邏輯。

4、Map+函數(shù)式接口

將上述策略類全部作為方法

@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>{
        //這里可以傳參啊,我這里舉例用不上參數(shù)
        //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);
        //這里防止活動編號沒匹配上,可以使用斷言來判斷從而拋出統(tǒng)一異常
        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);
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容