去掉 if...else 的七種絕佳之法...
當(dāng)前位置:點晴教程→知識管理交流
→『 技術(shù)文檔交流 』
我相信小伙伴一定看過多篇怎么去掉 if...else 的文章,也知道大家都很有心得,知道多種方法來去掉 if...else ,比如 Option,策略模式等等,但我相信大明哥這篇文章絕對是最全,最完備怎么去掉 if...else 的文章,里面有些方法我相信有小伙伴肯定不知道,我也不賣關(guān)子,直接進入主題,如何干掉 if...else。 方法一:提前 return假如有如下代碼: if (condition){ doSomething; } else { return; } 這種代碼我們一般采用提前 return 的方式,去掉不必要的 else。 if (!condition){ return } doSomething; 這種方法一般只適合分支結(jié)構(gòu)很簡單的 if...else,我們可以提前 return ,把一些不必要的 if...else 去掉。 方法二:枚舉枚舉其實也是可以去掉 if...else 的,如下: String orderStatusDes; if ("1".equals(orderStatus)) { orderStatusDes = "訂單未支付"; } else if ("2".equals(orderStatus)) { orderStatusDes = "訂單已支付"; } else if ("3".equals(orderStatus)) { orderStatusDes = "訂單已發(fā)貨"; } else if ("4".equals(orderStatus)) { orderStatusDes = "訂單已簽收"; } else if ("5".equals(orderStatus)) { orderStatusDes = "訂單已評價"; } 可能有小伙伴說,靠,誰會寫這種代碼?別這么絕對,大明哥工作這么久了,到現(xiàn)在依然看到有工作 5 、6 年的人寫這樣的代碼。這種類型的代碼非常適合枚舉來解決。 先定義一個枚舉類: @Getter @AllArgsConstructor public enum OrderStatusEnum { UN_PAID("1","訂單未支付"), PAIDED("2","訂單已支付"), SENDED("3","訂單已發(fā)貨"), SINGED("4","訂單已簽收"), EVALUATED("5","訂單已評價");
private String status;
private String statusDes;
static OrderStatusEnum of(String status) { for (OrderStatusEnum statusEnum : OrderStatusEnum.values()) { if (statusEnum.getStatus().equals(status)) { return statusEnum; } } return null; } } 有了這個枚舉,上面代碼直接可以優(yōu)化為一行代碼: String orderStatusDes = OrderStatusEnum.of(orderStatus).getStatusDes(); 當(dāng)然一般在實際項目中,這種處理方式也不是最佳的,最佳的方式應(yīng)該是在數(shù)據(jù)庫里面有一個碼值配置表,然后加載到系統(tǒng)緩存中來,在通過 code 去取值。當(dāng)然枚舉也是一種很好的解決方案。 方案三:Optional 判空我相信各位小伙伴的項目里面一定存在非空判斷,如果為空,則拋出異?;蛘?return。 Order order = getOrderById(id); if (order == null) { return "-1"; } else { return order.getOrderStatus(); } 對于這種代碼我們利用 Optional 可以非常優(yōu)雅地解決。 return Optional.ofNullable(order).map(o -> o.getOrderStatus()).orElse("-1"); 這種方式是不是非常優(yōu)雅,有格調(diào)。最后補充一句:
方案四:表驅(qū)動法表驅(qū)動法,是一種讓你可以在表中查找信息,而不必用過多的 if...else 來把他們找出來的方法。如下: if ("code1".equals(action)) { doAction1(); } else if ("code2".equals(action)) { doAction2(); } else if ("code3".equals(action)) { doAction3(); } else if ("code4".equals(action)) { doAction4(); } else if ("code5".equals(action)) { doAction5(); } 優(yōu)化方法如下: Map<String, Function<?> action> actionMap = new HashMap<>(); action.put("code1",() -> {doAction1()}); action.put("code2",() -> {doAction2()}); action.put("code3",() -> {doAction3()}); action.put("code4",() -> {doAction4()}); action.put("code5",() -> {doAction5()});
// 使用 actionMap.get(action).apply(); 其實這種方式也不是很好,因為它會顯得代碼非常臃腫。一種變形方案是將 //1. 先定義一個 ActionService 接口 public interface ActionService { void doAction(); }
//2. 然后定義 5 個實現(xiàn)類 public class ActionService1 implements ActionService{ public void doAction() { //do something } }
//3. 加入表中 Map<String, ActionService> actionMap = new HashMap<>(); action.put("code1",new ActionService1()); action.put("code2",new ActionService2()); action.put("code3",new ActionService3()); action.put("code4",new ActionService4()); action.put("code5",new ActionService5());
//4. 調(diào)用 actionMap.get(action).doAction(); 這種方式是不是比較優(yōu)雅些! 方案五:策略模式 + 工廠方法策略模式 + 工廠方法是解決 if...else 用得非常多的方案,它和上面的表驅(qū)動法有點兒類似。使用策略模式 + 工廠方法分為幾個步驟,以上面例子為例:
public class ActionService1 implements ActionService{ public void doAction() { //do something } }
public class ActionService2 implements ActionService{ public void doAction() { //do something } }
// 省略其他策略
public class ActionServiceFactory { private ActionServiceFactory(){
}
private static class SingletonHolder{ private static ActionServiceFactory instance=new ActionServiceFactory(); }
public static ActionServiceFactory getInstance(){ return SingletonHolder.instance; }
private static final Map<String,ActionService> ACTION_SERVICE_MAP = new HashMap<String, ActionService>();
static { ACTION_SERVICE_MAP.put("action1",new ActionService1()); ACTION_SERVICE_MAP.put("action2",new ActionService2()); ACTION_SERVICE_MAP.put("action3",new ActionService3()); ACTION_SERVICE_MAP.put("action4",new ActionService4()); ACTION_SERVICE_MAP.put("action5",new ActionService5()); }
public static ActionService getActionService(String actionCode) { ActionService actionService = ACTION_SERVICE_MAP.get(actionCode); if (actionService == null) { throw new RuntimeException("非法 actionCode"); } return actionService; }
public void doAction(String actionCode) { getActionService(actionCode).doAction(); } } 單例模式實現(xiàn)工廠類。
ActionServiceFactory.getInstance().doAction("action1"); 這種優(yōu)化方式也是很優(yōu)雅的,特別適合分支較多,邏輯較為復(fù)雜的代碼塊,這種方式將分支邏輯與業(yè)務(wù)代碼解耦了,是一種很不錯的方案。 方案六:責(zé)任鏈模式你想不到責(zé)任鏈模式也能優(yōu)化 if...else 吧。責(zé)任鏈我們可以看做是一個單鏈表的數(shù)據(jù)結(jié)構(gòu),一個對象一個對象地過濾條件,符合的就執(zhí)行,然后結(jié)束,不符合的就傳遞到下一個節(jié)點,如果每個對象都無法處理,一般都有一個最終的節(jié)點來統(tǒng)一處理。 我們依然以上面那個例子為例。
public abstract class ActionHandler { // 后繼節(jié)點 protected ActionHandler successor; /** * 處理請求 * @param actionCode */ public void handler(String actionCode) { doHandler(actionCode); } // 設(shè)置后繼節(jié)點 protected ActionHandler setSuccessor(ActionHandler successor) { this.successor = successor; return this; } // 處理請求 public abstract void doHandler(String actionCode); }
// 首節(jié)點,判斷 actionCode 是否為空 public class HeadHandler extends ActionHandler{
@Override public void doHandler(String actionCode) { if (StringUtils.isBlank(actionCode)) { throw new RuntimeException("actionCode 不能為空"); }
successor.doHandler(actionCode); } }
// 尾節(jié)點,直接拋出異常,因為到了尾節(jié)點說明當(dāng)前 code 沒有處理 public class TailHandler extends ActionHandler{
@Override public void doHandler(String actionCode) { throw new RuntimeException("當(dāng)前 code[" + actionCode + "] 沒有具體的 Handler 處理"); } }
public class ActionHandler1 extends ActionHandler{
@Override public void doHandler(String actionCode) { if ("action1".equals(actionCode)) { doAction1(); } else { // 傳遞到下一個節(jié)點 successor.doHandler(actionCode); } } }
public class ActionHandler2 extends ActionHandler{
@Override public void doHandler(String actionCode) { if ("action2".equals(actionCode)) { doAction2(); } else { // 傳遞到下一個節(jié)點 successor.doHandler(actionCode); } } }
// 省略其他節(jié)點
public class ActionHandlerFactory {
private ActionHandler headHandler;
private ActionHandlerFactory(){ headHandler = new HeadHandler(); ActionHandler actionHandler1 = new ActionHandler1(); ActionHandler actionHandler2 = new ActionHandler2(); ActionHandler actionHandler3 = new ActionHandler3(); ActionHandler actionHandler4 = new ActionHandler4(); ActionHandler actionHandler5 = new ActionHandler5();
ActionHandler tailHandler = new TailHandler();
// 構(gòu)建一條完整的責(zé)任鏈 headHandler.setSuccessor(actionHandler1).setSuccessor(actionHandler2).setSuccessor(actionHandler3). setSuccessor(actionHandler4).setSuccessor(actionHandler5).setSuccessor(tailHandler); }
private static class SingletonHolder{ private static ActionHandlerFactory instance=new ActionHandlerFactory(); }
public static ActionHandlerFactory getInstance(){ return SingletonHolder.instance; }
public void doAction(String actionCode) { headHandler.doHandler(actionCode); } }
ActionHandlerFactory.getInstance().doAction("action1"); 方案七:FunctionFunction 是 Java 8 中的函數(shù)式接口,利用好它我們可以極大地簡化我們的代碼,例如利用它我們可以輕松去掉我們的 if...else。比如有下面一段代碼: // 拋出異常 if (...) { throw new RuntimeException("哎呀,有異常哦...") }
// if...else 分支 if(...) { doSomething1(); } else { doSomething2(); } 現(xiàn)在我們利用 Function 來處理上面兩段代碼 處理拋出異常
@FunctionalInterface public interface ThrowExceptionFunction {
/** * 拋出異常 * @param message */ void throwMessage(String message); } 這里只需要有一個這樣的函數(shù)式接口就行,而且方法也沒有返回值,是一個消費型接口。
public class ValidateUtils {
/** * 拋出異常 * @param flag * @return */ public static ThrowExceptionFunction isTrue(Boolean flag) { return (errorMessage) -> { if (flag) { throw new RuntimeException(errorMessage); } }; } } ValidateUtils 類也是非常簡單的,如果傳入的 flag 為 true,則拋出異常。
ValidateUtils.isTrue(flag).throwMessage("哎呀,有異常哦..."); 使用方式是不是非常簡單? 處理 if...else 分支其實使用 Function 來去掉 if...else 分支我認(rèn)為有點兒偏門,因為它非常依賴我們定義的 Function 函數(shù),比如我們定義的方法只有兩個參數(shù),那它就只能處理處理兩個分支的,對于三個分支的 if...else 則需要重新定義方法。下面以兩個分支為例。
@FunctionalInterface public interface ActionHandler { void doActionHandler(ActionService trueActionService,ActionService falseActionService); } 函數(shù)式接口中定義了一個方法,
增加一個工具類,用來判斷為 true 時執(zhí)行哪個方法,為 false 時執(zhí)行哪個方法。 public class ActionHandlerUtils {
public static ActionHandler isTrue(Boolean flag) { return (trueActionService,falseActionService) -> { if (flag) { trueActionService.doAction(); } else { falseActionService.doAction(); } }; } }
ActionHandlerUtils.isTrue(true) .doActionHandler(() -> { //do true Something },() ->{ //do false Something }); 總結(jié)大明哥在這里總結(jié)了 7 中方式用來解決 if...else 的問題,我相信里面總有一兩種方案是你比較滿意的,七種方案各有優(yōu)劣,各自有各自的使用場景,我們需要在實踐中不斷領(lǐng)悟,在重構(gòu)中不斷進化,總結(jié)出適合自己最佳的重構(gòu)方案。
作者:大明哥_ 該文章在 2023/12/7 16:11:20 編輯過 |
關(guān)鍵字查詢
相關(guān)文章
正在查詢... |