LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

去掉 if...else 的七種絕佳之法...

admin
2023年12月7日 16:1 本文熱度 841

我相信小伙伴一定看過多篇怎么去掉 if...else 的文章,也知道大家都很有心得,知道多種方法來去掉 if...else ,比如 Option,策略模式等等,但我相信大明哥這篇文章絕對是最全,最完備怎么去掉 if...else 的文章,里面有些方法我相信有小伙伴肯定不知道,我也不賣關(guān)子,直接進(jìn)入主題,如何干掉 if...else。

方法一:提前 return

假如有如下代碼:

if (condition){

  doSomething;

} else {

  return;

}

這種代碼我們一般采用提前 return 的方式,去掉不必要的 else。

if (!condition){

  return

}

doSomething;

這種方法一般只適合分支結(jié)構(gòu)很簡單的 if...else,我們可以提前 return ,把一些不必要的 if...else 去掉。

方法二:枚舉

枚舉其實(shí)也是可以去掉 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 = "訂單已評價(jià)";

}

可能有小伙伴說,靠,誰會寫這種代碼?別這么絕對,大明哥工作這么久了,到現(xiàn)在依然看到有工作 5 、6 年的人寫這樣的代碼。這種類型的代碼非常適合枚舉來解決。

先定義一個(gè)枚舉類:

@Getter

@AllArgsConstructor

public enum OrderStatusEnum {

    UN_PAID("1","訂單未支付"),

    PAIDED("2","訂單已支付"),

    SENDED("3","訂單已發(fā)貨"),

    SINGED("4","訂單已簽收"),

    EVALUATED("5","訂單已評價(jià)");

 

    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;

    }

}

有了這個(gè)枚舉,上面代碼直接可以優(yōu)化為一行代碼:

String orderStatusDes = OrderStatusEnum.of(orderStatus).getStatusDes();

當(dāng)然一般在實(shí)際項(xiàng)目中,這種處理方式也不是最佳的,最佳的方式應(yīng)該是在數(shù)據(jù)庫里面有一個(gè)碼值配置表,然后加載到系統(tǒng)緩存中來,在通過 code 去取值。當(dāng)然枚舉也是一種很好的解決方案。

方案三:Optional 判空

我相信各位小伙伴的項(xiàng)目里面一定存在非空判斷,如果為空,則拋出異常或者 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)。最后補(bǔ)充一句:

防止 NPE,是程序員的基本修養(yǎng)

方案四:表驅(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();

其實(shí)這種方式也不是很好,因?yàn)樗鼤@得代碼非常臃腫。一種變形方案是將 doAction() 抽象成類。如下:

//1. 先定義一個(gè) ActionService 接口

public interface ActionService {

    void doAction();

}

 

//2. 然后定義 5 個(gè)實(shí)現(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ū)動法有點(diǎn)兒類似。使用策略模式 + 工廠方法分為幾個(gè)步驟,以上面例子為例:

  • 把條件模塊抽象為一個(gè)公共的接口,策略接口

    public interface ActionService {

        void doAction();

    }

  • 根據(jù)每個(gè)邏輯,定義出自己具體的策略實(shí)現(xiàn)類,如下:

public class ActionService1 implements ActionService{

    public void doAction() {

        //do something

    }

}

 

public class ActionService2 implements ActionService{

    public void doAction() {

        //do something

    }

}

 

// 省略其他策略

  • 工廠類,統(tǒng)一調(diào)度,用來管理這些策略,如下:

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

    }

}

單例模式實(shí)現(xiàn)工廠類。

  • 使用

ActionServiceFactory.getInstance().doAction("action1");

這種優(yōu)化方式也是很優(yōu)雅的,特別適合分支較多,邏輯較為復(fù)雜的代碼塊,這種方式將分支邏輯與業(yè)務(wù)代碼解耦了,是一種很不錯的方案。

方案六:責(zé)任鏈模式

你想不到責(zé)任鏈模式也能優(yōu)化 if...else 吧。責(zé)任鏈我們可以看做是一個(gè)單鏈表的數(shù)據(jù)結(jié)構(gòu),一個(gè)對象一個(gè)對象地過濾條件,符合的就執(zhí)行,然后結(jié)束,不符合的就傳遞到下一個(gè)節(jié)點(diǎn),如果每個(gè)對象都無法處理,一般都有一個(gè)最終的節(jié)點(diǎn)來統(tǒng)一處理。

我們依然以上面那個(gè)例子為例。

  • 定義責(zé)任鏈處理請求節(jié)點(diǎn)

public abstract class ActionHandler {

    // 后繼節(jié)點(diǎn)

    protected ActionHandler successor;

    /**

     * 處理請求

     * @param actionCode

     */

    public void handler(String actionCode) {

        doHandler(actionCode);

    }

    // 設(shè)置后繼節(jié)點(diǎn)

    protected ActionHandler setSuccessor(ActionHandler successor) {

        this.successor = successor;

        return this;

    }

    // 處理請求

    public abstract void doHandler(String actionCode);

}

  • 定義首尾節(jié)點(diǎn),用于一些異常情況的處理

// 首節(jié)點(diǎn),判斷 actionCode 是否為空

public class HeadHandler extends ActionHandler{

 

    @Override

    public void doHandler(String actionCode) {

        if (StringUtils.isBlank(actionCode)) {

            throw new RuntimeException("actionCode 不能為空");

        }

 

        successor.doHandler(actionCode);

    }

}

 

// 尾節(jié)點(diǎn),直接拋出異常,因?yàn)榈搅宋补?jié)點(diǎn)說明當(dāng)前 code 沒有處理

public class TailHandler extends ActionHandler{

 

    @Override

    public void doHandler(String actionCode) {

        throw new RuntimeException("當(dāng)前 code[" + actionCode + "] 沒有具體的 Handler 處理");

    }

}

  • 定義各個(gè)節(jié)點(diǎn)具體的實(shí)現(xiàn)節(jié)點(diǎn)

public class ActionHandler1 extends ActionHandler{

 

    @Override

    public void doHandler(String actionCode) {

        if ("action1".equals(actionCode)) {

            doAction1();

        } else {

            // 傳遞到下一個(gè)節(jié)點(diǎn)

            successor.doHandler(actionCode);

        }

    }

}

 

public class ActionHandler2 extends ActionHandler{

 

    @Override

    public void doHandler(String actionCode) {

        if ("action2".equals(actionCode)) {

            doAction2();

        } else {

            // 傳遞到下一個(gè)節(jié)點(diǎn)

            successor.doHandler(actionCode);

        }

    }

}

 

// 省略其他節(jié)點(diǎn)

  • 定義工廠,來構(gòu)建一條完整的責(zé)任鏈,并負(fù)責(zé)調(diào)度

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

方案七:Function

Function 是 Java 8 中的函數(shù)式接口,利用好它我們可以極大地簡化我們的代碼,例如利用它我們可以輕松去掉我們的 if...else。比如有下面一段代碼:

// 拋出異常

if (...) {

  throw new RuntimeException("哎呀,有異常哦...")

}

 

// if...else 分支

if(...) {

  doSomething1();

} else {

  doSomething2();

}

現(xiàn)在我們利用 Function 來處理上面兩段代碼

處理拋出異常

  • 定義拋出異常的形式的函數(shù)式接口

@FunctionalInterface

public interface ThrowExceptionFunction {

 

    /**

     * 拋出異常

     * @param message

     */

    void throwMessage(String message);

}

這里只需要有一個(gè)這樣的函數(shù)式接口就行,而且方法也沒有返回值,是一個(gè)消費(fèi)型接口。

  • 增加判斷工具類

public class ValidateUtils {

 

    /**

     * 拋出異常

     * @param flag

     * @return

     */

    public static ThrowExceptionFunction isTrue(Boolean flag) {

        return (errorMessage) -> {

            if (flag) {

                throw new RuntimeException(errorMessage);

            }

        };

    }

}

ValidateUtils 類也是非常簡單的,如果傳入的 flag 為 true,則拋出異常。isTrue() 返回值也是剛剛我們定義的 ThrowExceptionFunction。

  • 使用

ValidateUtils.isTrue(flag).throwMessage("哎呀,有異常哦...");

使用方式是不是非常簡單?

處理 if...else 分支

其實(shí)使用 Function 來去掉 if...else 分支我認(rèn)為有點(diǎn)兒偏門,因?yàn)樗浅R蕾囄覀兌x的 Function 函數(shù),比如我們定義的方法只有兩個(gè)參數(shù),那它就只能處理處理兩個(gè)分支的,對于三個(gè)分支的 if...else 則需要重新定義方法。下面以兩個(gè)分支為例。

  • 定義函數(shù)式接口

@FunctionalInterface

public interface ActionHandler {

    void doActionHandler(ActionService trueActionService,ActionService falseActionService);

}

函數(shù)式接口中定義了一個(gè)方法,doActionHandler(),它有兩個(gè)參數(shù),分別為:

  1. trueActionService:為 true 時(shí)要進(jìn)行的操作

  2. falseActionService:為 false 時(shí)要進(jìn)行的操作

  • 定義判斷方法

增加一個(gè)工具類,用來判斷為 true 時(shí)執(zhí)行哪個(gè)方法,為 false 時(shí)執(zhí)行哪個(gè)方法。

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)劣,各自有各自的使用場景,我們需要在實(shí)踐中不斷領(lǐng)悟,在重構(gòu)中不斷進(jìn)化,總結(jié)出適合自己最佳的重構(gòu)方案。

重構(gòu)之路,任重而道遠(yuǎn),各位其行且珍惜


作者:大明哥_
鏈接:https://juejin.cn/post/7296751524809048073
來源:稀土掘金


該文章在 2023/12/7 16:11:20 編輯過
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點(diǎn)晴ERP是一款針對中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場、車隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場作業(yè)而開發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉儲管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質(zhì)期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved

黄频国产免费高清视频,久久不卡精品中文字幕一区,激情五月天AV电影在线观看,欧美国产韩国日本一区二区
午夜性爱在线视频 | 在线看片免费视频 | 午夜成午夜成年片在线观看bd | 偷拍激情视频一区二区三区 | 日本另类一区二区 | 伊人久久综在合线亚洲2019人澡 |