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