前言
在很多時候,我們代碼中會有很多分支,而且分支下面的代碼又有一些復雜的邏輯,相信很多人都喜歡用 if-else/switch-case 去實現。做的不好的會直接把實現的代碼放在 if-else/switch-case 的分支之下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
switch ( type ) { case case1: ... ... break ; case case2: ... ... break ; case case3: ... ... break default : return null ; } |
這樣的代碼不僅冗長,讀起來也非常困難。做的好一點的會把這些邏輯封裝成函數然后在分支中調用:
1
2
3
4
5
6
7
8
9
10
|
switch ( type ) { case case1: return case1func(); case case2: return case2func(); case case3: return case3func(); default : return null ; } |
即使這樣也是面向過程思維的寫法,以前寫 c 程序的時候也總喜歡這樣寫,毫無設計模式可言。不僅違背開閉原則,而且隨著 switch-case 分支的增多,該段代碼只會越來越冗長。其實這種代碼已經有成熟的模式去消除諸多的 if-else/switch-case 分支。本文就教大家在 spring 中如何用注解+策略模式+簡單工廠的方式消除 if-else/switch-case 。我們就拿 qq 空間的個人中心舉例子,假如 qq 空間個人中心有四個 tab 分別是列出我的說說、我的日志、我的照片和我的訪客。一般的后臺代碼很有可能如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
//各個 tab 名稱的枚舉: public enum userrelatedtype { /** * 說說 */ shuoshuo( "說說" ), /** * 日志 */ rizhi( "日志" ), /** * 發布 */ 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 用戶個人中心相關 tab 的代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
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 ; } } |
而采用注解+策略模式+簡單工廠,重構后代碼如下:
1、定義一個注解,用來完全消除 if-else:
1
2
3
4
5
6
7
8
|
@target (elementtype.type) @retention (retentionpolicy.runtime) public @interface relatedtypeannotation { /** * 用戶相關類型名稱 */ userrelatedtype value(); } |
2、先定義了個接口,所有 tab 都要實現該接口。其中 list 是 tab 數據展示的方法。
1
2
3
4
5
6
7
8
9
10
|
public interface userrelated { /** * 列出詳細信息 * * @param query * @return */ list<userrelatedvo> list(userrelatedquery query); } |
3、定義具體的各個 tab 的實現,繼承 userrelated 策略接口
我的說說
1
2
3
4
5
6
7
8
9
|
@component ( "userrelatedshuoshuo" ) @relatedtypeannotation ( value = userrelatedtype.shuoshuo ) public class userrelatedshuoshuo implements userrelated { @override public list<userrelatedvo> list(userrelatedquery query) { system.out.println( "我的說說!" ); return list; } } |
我的日志
1
2
3
4
5
6
7
8
9
|
@component ( "userrelatedrizhi" ) @relatedtypeannotation ( value = userrelatedtype.rizhi ) public class userrelatedrizhi implements userrelated { @override public list<userrelatedvo> list(userrelatedquery query) { system.out.println( "我的日志!" ); return list; } } |
我的照片
1
2
3
4
5
6
7
8
9
|
@component ( "userrelatedzhaopian" ) @relatedtypeannotation ( value = userrelatedtype.zhaopian ) public class userrelatedzhaopian implements userrelated { @override public list<userrelatedvo> list(userrelatedquery query) { system.out.println( "我的照片!" ); return list; } } |
我的訪客
1
2
3
4
5
6
7
8
9
|
@component ( "userrelatedfangke" ) @relatedtypeannotation ( value = userrelatedtype.fangke ) public class userrelatedfangke implements userrelated { @override public list<userrelatedvo> list(userrelatedquery query) { system.out.println( "我的訪客!" ); return list; } } |
3、定義一個從 spring context 獲取 bean 的工具類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@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、定義一個簡單工廠,用來生產各種 tab 對象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
@component public class userrelatedfactory { @autowired springcontextutil springcontextutil; private static map<userrelatedtype, userrelated> userrelatedmap = maps.newconcurrentmap(); //工廠將 spring 裝配的相關的 bean 用 map 保存起來 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、調用的代碼(listrelated 會在 controller 中被調用)。
1
2
3
4
5
6
7
8
9
10
|
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 ; } } |
重構后的代碼如果需要再新增一種 tab,比如我的好友,只需要新增一種類型繼承 userrelated 實現其中的 list,并加上相應的注解即可。
其實這是一種通用的解決方案,當你 if-else/switch-case 的分支超過 3 個、且分支代碼相似且冗長的情況下就應該考慮這種模式。這種模式寫出的代碼面向對象、清晰、易擴展還高大上,何樂而不為呀,趕緊試試吧!
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對服務器之家的支持。
原文鏈接:https://juejin.im/post/5ca9f113e51d452b5e458ec3