在开发的过程中相信你也会写很多的if else语句吧,此篇主要来讲讲如何在日常开发的过程中尽量少的使用if else语句。
0x01 为什么要去if else
在开发的过程中我们可能会经常遇到if else的逻辑,写很多if else对于一位有情怀的程序员看来是不可以接收的,也影响阅读人的阅读感受,同时程序也违背了对修改关闭扩展开放的原则。在写程序的过程中我们应该尽量保证修改关闭,也就是说自己的写的代码逻辑应不该让别人在扩展逻辑的过程中进行修改,同时保证高的可扩展性。
在使用if else写程序的过程中你可能会写出如下的代码:
String strategy = "";if(strategy.equals("策略一")){ }else if(strategy.equals("策略二")){ }else if(...){ }else { }
当需要加一个分支逻辑就必须得去if else结构中改代码,这样不利于程序扩展,同时也非常难维护,如果业务复杂到一定的程度这块代码可能没法去重构了。
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 MapstrategyInfoMap = new HashMap (); 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; }}
如果需要扩展策略三,是不是只要添加自己的逻辑代码就行了呢?保证对修改关闭?答案是肯定的。可以如下方式来扩展策略三:
/* 在StrategyFactory中注入策略三的对应关系 */strategyInfoMap.put("策略三", new Strategy3());/* 然后定义策略三 */class Strategy3 implements StrategyInfo { public String getStrategyInfo(String strategy) { return strategy; }}
这样可非常方便的扩展策略四、策略五。
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 MapstrategyInfoMap = new HashMap (); 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的生命周期继续重构上面的实现方式。
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 MapstrategyInfoMap = new HashMap (); public void afterPropertiesSet() throws Exception { Map 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方式会追加到这里。