Spring如何消除代碼中的if-else/switch-case
前言
在很多時(shí)候,我們代碼中會(huì)有很多分支,而且分支下面的代碼又有一些復(fù)雜的邏輯,相信很多人都喜歡用 if-else/switch-case 去實(shí)現(xiàn)。做的不好的會(huì)直接把實(shí)現(xiàn)的代碼放在 if-else/switch-case 的分支之下:
switch ( type ) { case case1: ... ... break; case case2: ... ... break; case case3: ... ... break default: return null; }
這樣的代碼不僅冗長(zhǎng),讀起來(lái)也非常困難。做的好一點(diǎn)的會(huì)把這些邏輯封裝成函數(shù)然后在分支中調(diào)用:
switch ( type ) { case case1: return case1Func(); case case2: return case2Func(); case case3: return case3Func(); default: return null; }
即使這樣也是面向過(guò)程思維的寫法,以前寫 C 程序的時(shí)候也總喜歡這樣寫,毫無(wú)設(shè)計(jì)模式可言。不僅違背開(kāi)閉原則,而且隨著 switch-case 分支的增多,該段代碼只會(huì)越來(lái)越冗長(zhǎng)。其實(shí)這種代碼已經(jīng)有成熟的模式去消除諸多的 if-else/switch-case 分支。本文就教大家在 Spring 中如何用注解+策略模式+簡(jiǎn)單工廠的方式消除 if-else/switch-case 。我們就拿 QQ 空間的個(gè)人中心舉例子,假如 QQ 空間個(gè)人中心有四個(gè) tab 分別是列出我的說(shuō)說(shuō)、我的日志、我的照片和我的訪客。一般的后臺(tái)代碼很有可能如下:
//各個(gè) tab 名稱的枚舉: public enum UserRelatedType { /** * 說(shuō)說(shuō) */ SHUOSHUO("說(shuō)說(shuō)"), /** * 日志 */ RIZHI("日志"), /** * 發(fā)布 */ ZHAOPIAN("照片"), /** * 訪客 */ FANGKE(""); private String desc; UserRelatedType(String desc) { this.desc = desc; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } }
列出 QQ 用戶個(gè)人中心相關(guān) tab 的代碼:
public List<UserRelatedVO> listRelated(UserRelatedQuery query){ UserRelatedType relatedType = UserRelatedType.valueOf(StringUtils.upperCase(query.getType()) ); switch ( relatedType ) { case SHUOSHUO: return listRelatedShuoshuo( query ); case RIZHI: return listRelatedRizhi( query ); case ZHAOPIAN: return listRelatedZhaopian( query ); case FANGKE: return listRelatedFangke( query ); default: return null; } }
而采用注解+策略模式+簡(jiǎn)單工廠,重構(gòu)后代碼如下:
1、定義一個(gè)注解,用來(lái)完全消除 if-else:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface RelatedTypeAnnotation { /** * 用戶相關(guān)類型名稱 */ UserRelatedType value(); }
2、先定義了個(gè)接口,所有 tab 都要實(shí)現(xiàn)該接口。其中 list 是 tab 數(shù)據(jù)展示的方法。
public interface UserRelated { /** * 列出詳細(xì)信息 * * @param query * @return */ List<UserRelatedVO> list(UserRelatedQuery query); }
3、定義具體的各個(gè) tab 的實(shí)現(xiàn),繼承 UserRelated 策略接口
我的說(shuō)說(shuō)
@Component("userRelatedShuoshuo") @RelatedTypeAnnotation( value = UserRelatedType.SHUOSHUO ) public class UserRelatedShuoshuo implements UserRelated { @Override public List<UserRelatedVO> list(UserRelatedQuery query) { System.out.println("我的說(shuō)說(shuō)!"); return list; } }
我的日志
@Component("userRelatedRizhi") @RelatedTypeAnnotation( value = UserRelatedType.RIZHI ) public class UserRelatedRizhi implements UserRelated { @Override public List<UserRelatedVO> list(UserRelatedQuery query) { System.out.println("我的日志!"); return list; } }
我的照片
@Component("userRelatedZhaopian") @RelatedTypeAnnotation( value = UserRelatedType.ZHAOPIAN ) public class UserRelatedZhaopian implements UserRelated { @Override public List<UserRelatedVO> list(UserRelatedQuery query) { System.out.println("我的照片!"); return list; } }
我的訪客
@Component("userRelatedFangke") @RelatedTypeAnnotation( value = UserRelatedType.FANGKE ) public class UserRelatedFangke implements UserRelated { @Override public List<UserRelatedVO> list(UserRelatedQuery query) { System.out.println("我的訪客!"); return list; } }
3、定義一個(gè)從 Spring context 獲取 bean 的工具類
@Component public class SpringContextUtil implements ApplicationContextAware { private ApplicationContext context; public ApplicationContext getContext() { return context; } @Override public void setApplicationContext(ApplicationContext context)throws BeansException { this.context = context; } }
4、定義一個(gè)簡(jiǎn)單工廠,用來(lái)生產(chǎn)各種 tab 對(duì)象。
@Component public class UserRelatedFactory { @Autowired SpringContextUtil springContextUtil; private static Map<UserRelatedType, UserRelated> userRelatedMap = Maps.newConcurrentMap(); //工廠將 Spring 裝配的相關(guān)的 Bean 用 Map 保存起來(lái) public UserRelatedFactory(){ Map<String, Object> beanMap = springContextUtil.getContext().getBeansWithAnnotation(RelatedTypeAnnotation.class); for(Object userRelated : beanMap.values()) { RelatedTypeAnnotation annotation = userRelated.getClass().getAnnotation(RelatedTypeAnnotation.class); userRelatedMap.put(annotation.value(), (UserRelated)userRelated); } } public static UserRelated createRelated(UserRelatedType relatedType) { return userRelatedMap.get( relatedType ); } }
5、調(diào)用的代碼(listRelated 會(huì)在 controller 中被調(diào)用)。
public List<UserRelatedVO> listRelated(UserRelatedQuery query){ UserRelatedType relatedType = UserRelatedType.valueOf(StringUtils.upperCase(query.getType()) ); UserRelated related = UserRelatedFactory.createRelated( relatedType ); if( related != null ) { return related.list( query ); } else { return null; } }
重構(gòu)后的代碼如果需要再新增一種 tab,比如我的好友,只需要新增一種類型繼承 UserRelated 實(shí)現(xiàn)其中的 list,并加上相應(yīng)的注解即可。
其實(shí)這是一種通用的解決方案,當(dāng)你 if-else/switch-case 的分支超過(guò) 3 個(gè)、且分支代碼相似且冗長(zhǎng)的情況下就應(yīng)該考慮這種模式。這種模式寫出的代碼面向?qū)ο?、清晰、易擴(kuò)展還高大上,何樂(lè)而不為呀,趕緊試試吧!
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
Java使用PreparedStatement接口及ResultSet結(jié)果集的方法示例
這篇文章主要介紹了Java使用PreparedStatement接口及ResultSet結(jié)果集的方法,結(jié)合實(shí)例形式分析了PreparedStatement接口及ResultSet結(jié)果集的相關(guān)使用方法與操作注意事項(xiàng),需要的朋友可以參考下2018-07-07java集合框架的體系結(jié)構(gòu)詳細(xì)說(shuō)明
最近在一本J2EE的書中看到了很不錯(cuò)的對(duì)集合框架的說(shuō)明文章2012-11-11解決java數(shù)值范圍以及float與double精度丟失的問(wèn)題
下面小編就為大家?guī)?lái)一篇解決java數(shù)值范圍以及float與double精度丟失的問(wèn)題。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06Spring三級(jí)緩存思想解決循環(huán)依賴總結(jié)分析
這篇文章主要為大家介紹了Spring三級(jí)緩存思想解決循環(huán)依賴總結(jié)分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08Java 5個(gè)人坐在一起(有關(guān)第五個(gè)人歲數(shù)的問(wèn)題)
利用遞歸的方法,遞歸分為回推和遞推兩個(gè)階段。要想知道第五個(gè)人歲數(shù),需知道第四人的歲數(shù),依次類推,推到第一人(10歲),再往回推,需要的朋友可以參考下2017-02-02Java8新特性之Base64詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要為大家詳細(xì)介紹了Java8新特性之Base64的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06