美團一面:項目中有10000個ifelse如何優化?想了半天,被問懵了

架構的小事 2024-05-15 03:27:18

來源:https://mp.weixin.qq.com/s/MlGkFx5EimiLmBa5bckKoA

作者:Java技術棧

最近做 Java 面試輔導,有個兄弟面試美團,遇到一個特別有意思的問題:

一萬個 if else 如何優化,有好的解決方案嗎?

我看到這問題都有點懵逼,現實項目中怎麽可能會有 10000 個 if else 的代碼,至少我工作 10 余年沒見過樣的代碼。

關鍵要寫完這 10000 行的 if else 代碼,如果每天寫 100 個,是不是意味著也要 100 天才能寫完,並且每次請求都要執行幾千上萬次的判斷,代碼難以維護不說,還會嚴重影響系統性能。

很顯然,面試官考察的不是一般的八股文,這個問題可以看作是一道場景題,它考察一個程序員在面對複雜邏輯判斷時的優化能力,也是在考察一個程序員臨場發揮技術能力。

這兄弟雖然說上了策略模式,但顯然不是完美和唯一的解決方案,另外像責任鏈模式等其他設計模式都會存在這樣的問題,所以具體的問題還得具體分析。

所以這題可以這樣回答:

如果這 1 萬個 if else 是在同一個代碼塊流程裏面,這就要考慮這 1 萬 if else 存在的意義了,因爲這麽量極的 if else 會很難維護,也會極其影響性能,需要具體分析然後再去分析如何去分解和優化。如果這 1 萬個 if else 分散在同一個項目裏面,那麽優化 if else 的方式有很多種,包括.……

下面我說說幾種方案,歡迎大家拍磚。

if else 優化方案方案1:策略模式

這個兄弟也說到了策略模式,策略模式介紹及實戰看這篇:

別在再滿屏的 if/ else 了,試試策略模式,真香!!

使用策略模式確實可以提升代碼的優雅性,但也會存在以下問題:

如果是大量的 if else 分支,比如這 1 萬個,那就會有 1 萬個策略類,此時就會造成類膨脹,並且隨著時間的推移逐漸變得更加龐大而複雜。如果是多層的 if else 嵌套,策略模式可能也無法派上用場了。

策略模式的優點是可以很方便的解耦,適用于有多種不同邏輯和算法的 if 場景,但不適用于大量的 if else 場景。

方案2:策略模式變體

這是策略模式的一種變體:

Map<Integer, Runnable> actionMap = new HashMap<>();actionMap.put("condition1", () -> { /* 分支1的執行邏輯 */ });actionMap.put("condition2", () -> { /* 分支2的執行邏輯 */ });actionMap.put("conditionN", () -> { /* 分支N的執行邏輯 */ });// 根據條件獲取執行邏輯Runnable action = actionMap.get("condition1");if (action != null) { action.run();}

這種把業務邏輯代碼分離出去了,簡化了單個類的代碼,也省去了策略實現類,讓策略類不會得到膨脹,但如果有大量的條件映射,依然會造成單個類的膨脹和難以維護。

這裏使用的是線程異步執行的案例,還可以把要執行的邏輯代碼存儲在其他類、數據庫中,然後再用反射或者動態編譯的方式加載進去並執行。

方案3:多級嵌套優化

上面說的兩種方案嵌套可能無法解決,如果是這種帶層級的判斷是可以優化的:

/** 來源公衆號:Java技術棧 */if(xxxOrder != null){ if(xxxOrder.getXxxShippingInfo() != null){ if(xxxOrder.getXxxShippingInfo().getXxxShipmentDetails() != null){ if(xxxOrder.getXxxShippingInfo().getXxxShipmentDetails().getXxxTrackingInfo() != null){ ... } } }}

這種 if 嵌套層級太多,極不優雅,怎麽優化見我之前寫的這篇:

if else 太多?看我用 Java 8 輕松幹掉!

方案4:使用三目運算符

如果判斷條件不多,只有 2、3 個的情況下可以使用三目運算符簡化 if else 分支。

比如以下代碼:

String desc;if (condition1) { desc = "XX1";} else if (condition2) { desc = "XX2";} else { desc = "XX3";}

使用三目運算符一行搞定:

String desc = condition1 ? "XX1" : (condition2 ? "XX2" : "XX3");

超過 3 個條件就不建議使用了,不然代碼可讀性會大大降低。

方案5:使用枚舉

枚舉類型可以用來表示一組固定的值,例如星期幾、月份、顔色等,它提供了一種更簡潔、可讀性更高的方式來表示一組相關的常量。

如以下示例代碼:

/** * 公衆號:Java技術棧 */public Test { public static void main(String[] args) { Day today = Day.MONDAY; System.out.println("Today is " + today); System.out.println("Today is " + today.getChineseName()); } enum Day { MONDAY("星期一"), TUESDAY("星期二"), WEDNESDAY("星期三"), THURSDAY("星期四"), FRIDAY("星期五"), SATURDAY("星期六"), SUNDAY("星期日"); private String chineseName; Day(String chineseName) { this.chineseName = chineseName; } public String getChineseName() { return chineseName; } } }

這裏我只寫了一個字段,我們可以在枚舉屬性裏面定義多個字段,這樣就無需大量的 if else 判斷,直接通過枚舉來獲取某個某一組固定的值了。

方案6:使用 Optional

Java 8 提供了一個 Optional 新特性,它是一個可以包含 null 值的容器對象,可以用來代替 xx != null 的判斷。

參考我之前寫的這篇:

JDK 8 新特性之 Optional

如果項目中存在大量 xx != null 的判斷,可以使用 Optional 來優化。

方案7:盡快返回

分析業務,根據 if else 的執行次數按降序排,把執行次數較多的 if 放在最前面,如果符合條件,就使用 return 返回,如下面代碼:

if (條件1) { return}if (條件2) { return}...

這樣改可能是比較簡單的方式,在很大程度上可以提升系統的性能,但是還存在以下問題:

有的條件不能按執行次數排序,存在先後或者互斥關系。如果新增一個條件,可能無法馬上判定它的執行次數,如果放在後面可能也還會影響性能。對類的繼續膨脹和代碼維護沒有任何幫助。方案8:去除沒必要的 if else

比如這種:

if (condition) { ...} else { return;}

優化後:

if(!condition){ return;}

或者是這樣:

return !condition方案9:合並條件

考慮這 1 萬 if else 是不是真的每個都有必要,是不是可以合並歸類,比如是不是可以把幾百、幾千個相似邏輯的歸爲一類,這樣也能大大簡化 if else 數量。

比如以下代碼:

double calculateShipping() { if (orderAmount > 1000) { return 0.5; } if (customerLoyaltyLevel > 5) { return 0.5; } if (promotionIsActive) { return 0.5; }}

優化後:

double calculateShipping() { if (orderAmount > 1000 || customerLoyaltyLevel > 5 || promotionIsActive) { return 0.5; }}

這樣就把返回相同值的 if 歸爲一類了,如果 if 較大就能大大簡化代碼量。

方案10:規則引擎

對于複雜的業務邏輯,業務規則經常變化,規則制定不依賴于技術團隊,需要實現可配置的邏輯處理,此時可以考慮使用規則引擎來處理,比如 Drools。

規則引擎系統可用于執行一組規則,在許多業務應用程序中,業務決策可以通過一系列的邏輯規則來定義,規則引擎允許這些規則在運行時執行,而無需硬編碼在應用程序之中。

規則引擎的好處是:

業務邏輯可以和程序代碼解耦;提高業務邏輯的可管理性;提高系統的靈活性和可擴展性;業務人員可參與決策過程;總結

掌握優化 if else 的方法很重要,有時候面試官可能會換著法子問你,比如我們面試輔導這位兄弟遇到的這個面試官,你可以問清楚這一萬個 if else 是在一個代碼塊中,還是在一個項目中,然後再去解答,如果不了解清楚業務場景,盲目回答又會被面試官繞進去。

本文我也總結了 10 種優化 if else 的方法,其實還不止,根據不同的場景還可以使用多態、責任鏈模式、模板方法模式等更多方法來消除 if else。

總之,消除 if else 並沒有萬能的方法,也不可能全部優化掉,在實際開發中需要根據實際場景使用不同的方法,以及多種方法組合使用,這樣才是正確的方式。

0 阅读:0

架構的小事

簡介:感謝大家的關注