前言
隨着項目的迭代,代碼中存在的分支判斷可能會越來越多,當里面涉及到的邏輯比較復雜或者分支數量實在是多的難以維護的時候,我們就要考慮下,有辦法能讓這些代碼變得更優雅嗎?
正文
使用枚舉
這里我們簡單的定義一個表示狀態的枚舉。
public enum Status { NEW(0),RUNNABLE(1),RUNNING(2),BLOCKED(3),DEAD(4); public int statusCode; Status(int statusCode){ this.statusCode = statusCode; } }
那么我們在使用的時候就可以直接通過枚舉調用了。
int statusCode = Status.valueOf("NEW").statusCode;
優雅的解決了下面代碼賦值的方式
if(param.equals("NEW")){ statusCode = 0; }else if(param.equals("RUNNABLE")){ statusCode = 1; } ...
善用 Optional
在項目中,總少不了一些非空的判斷,可能大部分人還是如下的用法
if(null == user){ //action1 }else{ //action2 }
這時候該掏出Optional這個秘密武器了,它可以讓非空校驗更加優雅,間接的減少if操作。沒了解過Optional的同學可自行Google,這里就不再贅述。
Optional<User> userOptional = Optional.ofNullable(user);
userOptional.map(action1).orElse(action2);
上面的代碼跟第一段是等效的,通過一些新特性讓代碼更加緊湊。
表驅動法
來自Google的解釋:表驅動法是一種編程模式,它的本質是,從表里查詢信息來代替邏輯語句(if,case)。下面看一個案例,通過月份來獲取當月的天數(僅作為案例演示,獲取2月份的數據不嚴謹),普通做法:
int getMonthDays(int month){ switch(month){ case 1:return 31;break; case 2:return 29;break; case 3:return 31;break; case 4:return 30;break; case 5:return 31;break; case 6:return 30;break; case 7:return 31;break; case 8:return 31;break; case 9:return 30;break; case 10:return 31;break; case 11:return 30;break; case 12:return 31;break; default:return 0; } }
表驅動法實現方式
int monthDays[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int getMonthDays(int month){ return monthDays[--month]; }
其實這里的表就是數組而已,通過直接查詢數組來獲得需要的數據,那么同理,Map之類的容器也可以成為我們編程概念中的表。
Map<?, Function<?> action> actionsMap = new HashMap<>(); // 初試配置對應動作 actionsMap.put(value1, (someParams) -> { doAction1(someParams)}); actionsMap.put(value2, (someParams) -> { doAction2(someParams)}); actionsMap.put(value3, (someParams) -> { doAction3(someParams)}); // 省略 null 判斷 actionsMap.get(param).apply(someParams);
通過Java8的lambda表達式,我們把需要執行東西存進value中,調用的時候通過匹配key的方式進行。
提前判斷返回
在之前的文章《優化代碼里的 “ 壞味道 ”》里也有提過,如下語句
if(condition){ //dost }else{ return ; }
改為
if(!condition){ return ; } //dost
避免一些不必要的分支,讓代碼更精煉。
其他方法
除了上面提到的方法,我們還可以通過一些設計模式,例如策略模式,責任鏈模式等來優化存在大量if,case的情況,其原理會和表驅動的模式比較相似,大家可以自己動手實現一下,例如我們在Netty的使用過程中,可能會出現需要大量判斷不同的命令去執行對應動作的場景。
ServerHandler.java if(command.equals("login")){ //執行登錄 }else if(command.equals("chat")){ //聊天 }else if(command.equals("broadcast")){ //廣播信息 } ....
該如何處理呢?這里先賣個關子,大家可以先思考一下,筆記后續會寫一些關於Netty實現IM的文章,到時候會詳細介紹。
結語
最后要明確一點,不是所有的if/else,switch/case都需要優化,當我們發現有“痛點”或者“聞到代碼有壞味道”再來優化才是最好的,不然你可能會寫了一個從不擴展的可擴展代碼,所有的優化都是為了更好的迭代項目,更好的服務於業務,而不是為了優化而優化。
公眾號博文同步Github倉庫,有興趣的朋友可以幫忙給個Star哦,碼字不易,感謝支持。
推薦閱讀
關注「深夜里的程序猿」,分享最干的干貨
