摘要:在開發的過程中相信你也會寫很多的語句吧,此篇主要來講講如何在日常開發的過程中盡量少的使用語句。策略一單例模式這種單例模式在類一加載的時候就將單例對象創建完畢,總是這個對象存在內存中,避免了通過線程同步來生成對象,線程安全的創建方式。
在開發的過程中相信你也會寫很多的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方式會追加到這里。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/64894.html
摘要:源碼剖析之設計模式鑒賞策略模式小結在這篇文章中筆者和大家分享幾個減少的小由于這些都會有一定的限制因此還向大家介紹了幾個能夠避免寫出糟糕的的設計模式并使用觀察者模式簡單的改進了仲裁者模式的例子 本文首發于數據浮云:https://mp.weixin.qq.com/s?__... 在寫代碼的日常中,if...else語句是極為常見的.正因其常見性,很多同學在寫代碼的時候并不會去思考其在目...
摘要:對之前來說,沒有一等函數,就要把每個條件判斷寫成接口的實現類。需要前后鏈接,節點對其后的子鏈有控制力,所以不那么像。 另載于 http://www.qingjingjie.com/blogs/8 前段時間知乎上有人發了這么個段子: 某日,老師在課堂上想考考學生們的智商,就問一個男孩: 樹上有十只鳥,開槍打死一只,還剩幾只? 男孩反問:是無聲手槍,還是其他沒有聲音的槍么? 不是. ...
摘要:本期大綱確定縱坐標的范圍并繪制根據真實數據繪制折線相關閱讀在微信小程序中繪制圖表在微信小程序中繪制圖表關注我的項目查看完整代碼。相關閱讀在微信小程序中繪制圖表在微信小程序中繪制圖表 本期大綱 1、確定縱坐標的范圍并繪制 2、根據真實數據繪制折線 相關閱讀:在微信小程序中繪制圖表(part1)在微信小程序中繪制圖表(part3) 關注我的 github 項目 查看完整代碼。 確定縱坐...
閱讀 1139·2021-11-08 13:13
閱讀 1721·2019-08-30 15:55
閱讀 2773·2019-08-29 11:26
閱讀 2439·2019-08-26 13:56
閱讀 2561·2019-08-26 12:15
閱讀 2143·2019-08-26 11:41
閱讀 1404·2019-08-26 11:00
閱讀 1543·2019-08-23 18:30