1. 程式人生 > >Java-Annotation的一種用法(消除程式碼中冗餘的if/else或switch語句)

Java-Annotation的一種用法(消除程式碼中冗餘的if/else或switch語句)

# Java-Annotation的一種用法(消除程式碼中冗餘的if/else或switch語句) ### 1.冗餘的if/else或switch ​ 有沒有朋友寫過以下的程式碼結構,大量的if/esle判斷,來選擇不同的執行方式 ```java if(type==1001){ return decodeMsg1001(msg); }else if(type==1002){ return decodeMsg1002(msg); } ..... ``` ​ 或者上面的程式碼也是可以轉換成相應的switch語句來執行,結構如下所示: ```java switch(type){ case 1001:{ return decodeMsg1001(msg) } case 1002:{ return decodeMsg1002(msg); } .... } ``` ​ 總之,如果type的值很多的話,就會導致這段程式碼特別的長。如果想在處理訊息的函式中新增一些其他的資訊,則會導致處理訊息的函式體也會比較長。 ​ **Java語言是面向物件的,有沒有一種方法用面向物件的方式來解決這個問題。將大量的if/else語句轉換成使用介面的方式來解決**。答案是有的 ### 2.思路想法 ​ 上述的問題大多數產生在,多個不同型別的訊息對應著不同的處理方法(不同訊息所對應的資料不一致)。 ​ 可以將不同的型別與型別所對應的處理方法,做成一個對映表。即一種type對應於一個typeProcessor,在java中這種資料結構是Map。所以在系統初始化時,先生成這樣一種Map的對應關係。當一種型別type的訊息到來時,從這個map中查找出所對應的處理類,然後動態產生一個介面物件,然後執行介面中的方法。那這樣就會有相應的問題: - 問題一:每一種型別對應一個處理類,就會有好多實體類,怎麼做好一個型別對應一個處理類 - 問題二:如果一個一個類實體物件的手動新增,也會產生好多冗餘的程式碼。 ### 3.訊息對應實現 #### 3.1 利用annotation實現型別與處理類對應 ​ 在java中可以利用Annotation這一特性,來實現訊息型別與實體類的對應,先建立一個annotation。 ```java @Target(ElementType.TYPE) //TYPE(型別)是指可以用在Class,Interface,Enum和Annotation型別上. @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ProtocolCommand { int msgCommand() default 0 ; } ``` ​ 建立好相應的Annotation後,可以新增在每一個訊息處理類上,在Annotation中有一個屬性為msgCommand,是int型別的,這樣就可以做到對應。 #### 3.2訊息處理介面 ​ 為方便操作,可以建立一個訊息處理介面,對應每一種型別的訊息處理類都需要實現這一介面,這樣的好處在動態產生物件很好的做到統一處理。 ```java public interface IUbloxMsg { public int decodeUbxMsg(RawData rawData); } ``` ​ 這裡的介面很簡單,如果想處理複雜的業務,可以自行在介面中新增相應的方法。 ​ **這裡也可以不用介面這一特性來實現功能,也可以用抽象類 來實現。每一種特性都可以實現功能。** #### 3.3具體訊息實現 ```java @ProtocolCommand(msgCommand=UbloxConstant.ID_NAVSOL) public class NavSolUbloxMsgImpl implements IUbloxMsg { public int decodeUbxMsg(RawData rawData) { return 0; } } ``` ​ 可以看到在具體的訊息型別處理類上,加上我們自定義的註解,即可實現具體訊息型別與具體訊息處理類對應。 ### 4.生成Map訊息型別對映 #### 4.1訊息處理類掃描,得到Class集合 ​ 通常情況下,為了方便管理訊息處理類應該放在一個包目錄下。所以我們需要自動掃描出這個包目錄下的所有的class,產生Class集合。然後在這個集合中查詢到有我們自定義註解的類,同時得到註解物件,獲取訊息型別,並將此訊息型別新增至Map訊息對映中。 ​ 類掃描程式碼核心部分程式碼如下: ```java public static ClassFilter cFilter = new ClassFilter(true); //傳入的引數為包名 public st