如何避免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方式会追加到这里。

相关文章
相关标签/搜索