如何避免if else

在開發的過程當中相信你也會寫不少的if else語句吧,此篇主要來說講如何在平常開發的過程當中儘可能少的使用if else語句。java

0x01 爲何要去if else

在開發的過程當中咱們可能會常常遇到if else的邏輯,寫不少if else對於一位有情懷的程序員看來是不能夠接收的,也影響閱讀人的閱讀感覺,同時程序也違背了對修改關閉擴展開放的原則。在寫程序的過程當中咱們應該儘可能保證修改關閉,也就是說本身的寫的代碼邏輯應不應讓別人在擴展邏輯的過程當中進行修改,同時保證高的可擴展性。c++

在使用if else寫程序的過程當中你可能會寫出以下的代碼:程序員

String strategy = "";
if(strategy.equals("策略一")){
    
}else if(strategy.equals("策略二")){
    
}else if(...){
    
}else {
    
}

當須要加一個分支邏輯就必須得去if else結構中改代碼,這樣不利於程序擴展,同時也很是難維護,若是業務複雜到必定的程度這塊代碼可能無法去重構了。spring

0x02 策略模式 + 工廠模式 + 單例模式

在想到要去掉if else這種結構來寫代碼,首先容易想到的是經過一個map來保存key對應的邏輯,做爲一個從c++轉到java開發的程序的思惟是經過函數指針來解決問題,可是java並無這麼個東西,因此就有了下面這段代碼邏輯了。安全

public class StrategyTest {

    public static void main(String[] args) {
        String result = ObtainStrategyInfo.getInstance().getStrategyInfo("策略一");
        System.out.println(result);
    }
}

/* (單例模式) */
class ObtainStrategyInfo {

    private static final ObtainStrategyInfo obtainStrategyInfo = new ObtainStrategyInfo();

    public static ObtainStrategyInfo getInstance(){
        return obtainStrategyInfo;
    }

    public String getStrategyInfo(String strategy){
        StrategyInfo strategyInfo = new StrategyFactory().getStrategyInfoClass(strategy);
        return strategyInfo.getStrategyInfo(strategy);
    }
}
這種單例模式在類一加載的時候就將單例對象建立完畢,老是這個對象存在內存中,避免了經過線程同步來生成對象,線程安全的建立方式。

/* 其實最終的if else判斷邏輯都在這裏了 (工廠模式)*/
class StrategyFactory {
    private static Map<String, StrategyInfo> strategyInfoMap = new HashMap<String, StrategyInfo>();

    static {
        strategyInfoMap.put("策略一", new Strategy1());
        strategyInfoMap.put("策略二", new Strategy2());
    }

    public StrategyInfo getStrategyInfoClass(String strategy){
        StrategyInfo strategyInfo = null;
        for(String key : strategyInfoMap.keySet()){
            if(strategy.equals(key)) {
                strategyInfo = strategyInfoMap.get(key);
            }
        }
        return strategyInfo;
    }
}

/* (策略模式) */
interface StrategyInfo {
    String getStrategyInfo(String strategy);
}

class Strategy1 implements StrategyInfo {

    public String getStrategyInfo(String strategy) {
        return strategy;
    }
}

class Strategy2 implements StrategyInfo {

    public String getStrategyInfo(String strategy) {
        return strategy;
    }
}

若是須要擴展策略三,是否是隻要添加本身的邏輯代碼就好了呢?保證對修改關閉?答案是確定的。能夠以下方式來擴展策略三:app

/* 在StrategyFactory中注入策略三的對應關係 */
strategyInfoMap.put("策略三", new Strategy3());

/* 而後定義策略三 */
class Strategy3 implements StrategyInfo {

    public String getStrategyInfo(String strategy) {
        return strategy;
    }
}

這樣可很是方便的擴展策略4、策略五。ide

0x03 優化版(策略模式 + 工廠模式 + 單例模式)

上面講到的(策略模式 + 工廠模式 + 單例模式)來去if else的實現方式,仍是存在一些微小的問題,仍是須要手動去工廠中去註冊新增長的策略,本版塊結合spring bean的生命週期作到後續擴展只須要增長本身的策略就行,策略類在被spring實例化得生命週期中實現向工廠中註冊本身。函數

public class StrategyTest {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/config/applicationContext.xml");
        String result = ObtainStrategyInfo.getInstance().getStrategyInfo("策略一");
        System.out.println(result);

    }
}

class ObtainStrategyInfo {

    private static final ObtainStrategyInfo obtainStrategyInfo = new ObtainStrategyInfo();
    private StrategyFactory strategyFactory = new StrategyFactory();

    public static ObtainStrategyInfo getInstance(){
        return obtainStrategyInfo;
    }

    public String getStrategyInfo(String strategy){
        StrategyInfo strategyInfo = strategyFactory.getStrategyInfoClass(strategy);
        return strategyInfo.getStrategyInfo(strategy);
    }
}

class StrategyFactory {
    private static Map<String, StrategyInfo> strategyInfoMap = new HashMap<String, StrategyInfo>();

    public StrategyInfo getStrategyInfoClass(String strategy){
        return strategyInfoMap.get(strategy);
    }

    /* 被策略調用實現自動註冊 */
    public static void addStrategyForFactory(String strategyName, StrategyInfo strategyInfo) {
        strategyInfoMap.put(strategyName, strategyInfo);
    }
}

interface StrategyInfo {
    String getStrategyInfo(String strategy);
}

class Strategy1 implements StrategyInfo, InitializingBean {

    private static final String identify = "策略一";

    public String getStrategyInfo(String strategy) {
        return "策略一 " + strategy;
    }

    /* Strategy2的對象在初始化完成後會調用這個生命週期函數 */
    public void afterPropertiesSet() throws Exception {
        StrategyFactory.addStrategyForFactory(identify, this);
    }
}

class Strategy2 implements StrategyInfo, InitializingBean {

    private static final String identify = "策略一";
    public String getStrategyInfo(String strategy) {
        return "策略二 " + strategy;
    }
    
    public void afterPropertiesSet() throws Exception {
        StrategyFactory.addStrategyForFactory(identify, this);
    }
}

後面再對策略進行新增的時候只須要都實現InitializingBean這個接口的afterPropertiesSet方法就再本身實例化後向StrategyFactory中註冊本身,極大的下降了擴展成本。優化

0x04 spring應用上下文 + spring bean生命週期

spring bean的生命週期是個很好被利用的技巧,這裏咱們又利用了sping應用上下文和bean的生命週期繼續重構上面的實現方式。this

public class StrategyTest {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/config/applicationContext.xml");
        StrategyLoader strategyLoader = applicationContext.getBean(StrategyLoader.class);
        String result = strategyLoader.getStrategyInfo("策略一");
        System.out.println(result);

    }
}

class StrategyLoader implements InitializingBean, ApplicationContextAware{
    private ApplicationContext applicationContext;
    private static Map<String, StrategyInfo> strategyInfoMap = new HashMap<String, StrategyInfo>();

    public void afterPropertiesSet() throws Exception {
        Map<String, StrategyInfo> strategyInfos = applicationContext.getBeansOfType(StrategyInfo.class);
        if(CollectionUtils.isEmpty(strategyInfos)) {
            return;
        }

        for(String key : strategyInfos.keySet()) {
            strategyInfoMap.put(strategyInfos.get(key).getIdentify(), strategyInfos.get(key));
        }
    }

    public String getStrategyInfo(String strategy){
        StrategyInfo strategyInfo = strategyInfoMap.get(strategy);
        if(strategyInfo != null) {
            return strategyInfo.getStrategyInfo(strategy);
        }
        return "";
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

interface StrategyInfo {
    String getStrategyInfo(String strategy);
    String getIdentify();
}

class Strategy1 implements StrategyInfo {

    private static final String identify = "策略一";

    public String getStrategyInfo(String strategy) {
        return "策略一 " + strategy;
    }

    public String getIdentify(){
        return identify;
    }
}

class Strategy2 implements StrategyInfo {

    private static final String identify = "策略一";
    public String getStrategyInfo(String strategy) {
        return "策略二 " + strategy;
    }

    public String getIdentify(){
        return identify;
    }
}

這是咱們擴展策略就更加簡單方便了,咱們只須要正常的實現StrategyInfo接口,以實現動態擴展。

0x05 後記

後面若是遇到好的去掉if else方式會追加到這裏。

相關文章
相關標籤/搜索