Java中的常量治理


版權聲明:本文為博主原創文章,轉載請注明出處,歡迎使勁噴

 

雖然推崇在java中使用枚舉(可查看《Java中的枚舉的治理》)來對數據字典及常量進行控制,但是有些時候,我們還是會覺得常量控制更為便捷。

比如,對於數據字典,我們可以使用枚舉值來處理;對於一些其他的信息,我們會使用常量保存和使用。

 

一、常量遇到的問題

1.苗條的常量類

這里使用苗條形容下我們程序中的常量類,別看它寬度,就只看她長度,滾起屏來,那叫一個長啊,修長的身材,令你如痴如醉。(省略號里的東西,我就不貼了!!!)

例如:

public class Constants {

        public static final String REAL_NAME1 = "v1";
        public static final String REAL_NAME2 = "v2";
        public static final String REAL_NAME3 = "v3";
        public static final String REAL_NAME4 = "v4";
        public static final String REAL_NAME5 = "v5";
        public static final String 6 = "v6";
        public static final String 7 = "v7";
        public static final String REAL_NAME8 = "v8";
        public static final String REAL_NAME9 = "v9";
        ......
}

   一個無窮盡的常量類,設想這個類篇幅巨長,你想加點什么不知道該加在哪;你想改點什么,不知道去哪改;你想罵街也不知道去哪罵!!!

這樣的常量管理,帶來的問題如下:

  a.不好維護,相關的代碼寫到一起,此時,常量的篇幅較長導致你找不到對應的常量塊進行維護;

  b.雖然是在不同的業務場景下,但是有些常量的名稱還是有可能重復;

  c.有時為了減少常量的定義,就得共用一些常量,而這樣的共用會導致某種業務場景下需要對該常量進行修改,而導致另外一些業務場景下的常量使用產生歧義;

  d.其他你能想到的罵街的理由

2.代碼的壞味道

引用下“代碼的壞味道”這個詞,我們常能看到一些常量類的壞味道里,假如常量名稱如上所示,名稱類似的很多;名稱不明確的也很多,還沒有注釋,這樣的歧義也是因為代碼不好管理造成的。

二、常量如何治理

1.初級治理——使用內部類

  使用java的內部類進行常量的初步治理,代碼如下:

/**
 * Created by SZBright on 2017/3/1.
 *
 * @author :
 */
public class Constants {

    public static final class TOKEN_FLAG_ONE {

        public static final String REAL_NAME = "v1";

        public static final String CRET = "v2";

        public static final String GUR = "v5";

    }

}

  這樣的好處是,通過常量的內部類的名稱,可以直接獲取對應模塊的常量的引用信息。使用代碼如下:

    @Test
    public void test(){
        System.out.println(Constants.TOKEN_FLAG_ONE.REAL_NAME);
    }

 

2.中極治理——集中管理

  初級治理中,我們的想法還是不錯的,但是看起來比較low,而且當我們希望通過value獲取到key時,你卻無能為力,於是我們有了中級治理。

  中級治理我們主要是通過map,每個內部類都會存為map中的一個entry,每個entry又都是map類型的集合,集合中包含該內部類的所有常量。

  代碼如下:

/**
 * Created by SZBright on 2017/3/1.
 *
 * @author :
 */
public class Constants {

    public static final Map<String,Map<String,String>> keyValueMapCons = new LinkedHashMap<String, Map<String, String>>();

    public static final Map<String,Map<String,String>> valueKeyMapCons = new LinkedHashMap<String, Map<String, String>>();
  /**
     * 初始化所有常量
     */
    static {
        try {
            //獲取所有內部類
            for (Class cls : Constants.class.getClasses()) {
                Map<String, String> keyValueMap = new LinkedHashMap<String, String>();//存放key和value的map
                Map<String, String> valueKeyMap = new LinkedHashMap<String, String>();//存放value和key的map//每個內部類-獲取所有屬性(不包括父類的)
                for (Field fd : cls.getDeclaredFields()) {
                    keyValueMap.put(fd.getName(), fd.get(cls).toString());//注解對象空,其值為該field的值
                    valueKeyMap.put(fd.get(cls).toString(),fd.getName());
                }
                keyValueMapCons.put(cls.getSimpleName(),keyValueMap);
                valueKeyMapCons.put(cls.getSimpleName(),valueKeyMap);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
public static final class TOKEN_FLAG_ONE { public static final String REAL_NAME = "v1"; public static final String CRET = "v2"; public static final String GUR = "v5"; } }

 

  好了,我們在Constants中有了兩個常量集:一個集keyValueMapCons,按照內部類的名稱,把常量的名字作為map的key,值作為map的value;一個集valueKeyMapCons,按照內部類的名稱,把常量的值作為map的key,常量的名字作為map的key。

  這樣一來,我們可以使用常量的這兩個集滿足我們對常量的使用需求。使用代碼如下:

    @Test
    public void test1(){
        System.out.println(Constants.keyValueMapCons.get("TOKEN_FLAG_ONE").get("REAL_NAME"));//v1
        System.out.println(Constants.valueKeyMapCons.get("TOKEN_FLAG_ONE").get("v5"));//GUR
    }

 

3.中高級治理——使用注解

  我們可以通過key獲取到value,也可以通過value獲取到key了。現在有這么個問題,我們使用常量時,不光要有常量的定義、常量的值,還應該有對常量的描述,而傳統的對於常量的定義,往往使我們無從存放對常量的描述。

  此時,我們希望通過注解來改變這種情況。

  我們來自定義注解類型如下:

/**
 * Created by SZBright on 2017/3/1.
 *
 * @author :
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface ConstantAnnotation {
    String value();
}

 

  有了這個注解,我們就可以把描述些到常量的上面了

/**
 * Created by SZBright on 2017/3/1.
 *
 * @author :
 */
public class Constants {
    private static final String CONSTANT_STRING = "這是一條短信消息";

    public static final class TOKEN_FLAG_ONE {

        @ConstantAnnotation("實名")
        public static final String REAL_NAME = "v1";

        @ConstantAnnotation("證書")
        public static final String CRET = "v2";

        @ConstantAnnotation(CONSTANT_STRING)
        public static final String GUR = "v5";//把描述與注解分開

    }
}

  我們看到,每個常量上面有了對應的中文描述,這樣的中文描述可以用來干嘛呢?

  比如,我們希望在某個業務場景下,符合gur常量的業務,發送一條短信消息,而這個消息我們就可以定義在我們的自定義注解中。例如GUR這個常量,我們把它的描述聲明成一個常量,這個常量可用來存放對應的短信消息。我們的常量類中如果再有一個通過常量獲取到描述的map,這是不是就完美了?

  於是,我們有了下面的代碼:

/**
 * Created by SZBright on 2017/3/1.
 *
 * @author :
 */
public class Constants {

    public static final Map<String,Map<String,String>> keyDescMapCons = new LinkedHashMap<String, Map<String, String>>();
/**
     * 初始化所有常量
     */
    static {
        try {
            //獲取所有內部類
            for (Class cls : Constants.class.getClasses()) {
                Map<String, String> keyDescMap = new LinkedHashMap<String, String>();//存放key和desc的map

                //每個內部類-獲取所有屬性(不包括父類的)
                for (Field fd : cls.getDeclaredFields()) {
                    //每個屬性獲取指定的annotation的注解對象
                    ConstantAnnotation ca = fd.getAnnotation(ConstantAnnotation.class);
                    if(ca != null){
                        keyDescMap.put(fd.getName(), ca.value());//注解對象不空,其值為注解對象中的值
                    }
                }
                                keyDescMapCons.put(cls.getSimpleName(),keyDescMap);
                
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * key-value-desc
     *
     * 常量名-常量值-注解描述
     *
     * 實現通過key獲取value
     *
     * 實現通過key獲取desc
     *
     * 實現通過value獲取desc
     */
    private static final String CONSTANT_STRING = "這是一條短消息";

    public static final class TOKEN_FLAG_ONE {

        @ConstantAnnotation("實名")
        public static final String REAL_NAME = "v1";

        @ConstantAnnotation("證書")
        public static final String CRET = "v2";

        @ConstantAnnotation(CONSTANT_STRING)
        public static final String GUR = "v5";//把描述與注解分開

    }

}

 

   現在,我們通過Constants的keyDescMap可以獲取到這個常量對應的描述了。使用代碼如下:

    @Test
    public void test1(){
        System.out.println(Constants.keyDescMapCons.get("TOKEN_FLAG_ONE").get("GUR"));//打印輸出“這是一條短消息”
    }

 

4.綜合治理(終極治理)

  現在我們有了常量的治理,有了注解的描述,有時我們需要通過key獲取到value,有時我們需要通過value獲取描述,有時我們需要通過key獲取到描述,等等。排列組合共6種形式,暫且不說什么時候會用到,我們先給他來個綜合治理的實現。代碼如下:

/**
 * Created by SZBright on 2017/3/1.
 *
 * @author :
 */
public class Constants {

    public static final Map<String,Map<String,String>> keyValueMapCons = new LinkedHashMap<String, Map<String, String>>();

    public static final Map<String,Map<String,String>> keyDescMapCons = new LinkedHashMap<String, Map<String, String>>();

    public static final Map<String,Map<String,String>> descValueMapCons = new LinkedHashMap<String, Map<String, String>>();

    public static final Map<String,Map<String,String>> descKeyMapCons = new LinkedHashMap<String, Map<String, String>>();

    public static final Map<String,Map<String,String>> valueDescMapCons = new LinkedHashMap<String, Map<String, String>>();

    public static final Map<String,Map<String,String>> valueKeyMapCons = new LinkedHashMap<String, Map<String, String>>();


    /**
     * 初始化所有常量
     */
    static {
        try {
            //獲取所有內部類
            for (Class cls : Constants.class.getClasses()) {
                Map<String, String> keyDescMap = new LinkedHashMap<String, String>();//存放key和desc的map
                Map<String, String> keyValueMap = new LinkedHashMap<String, String>();//存放key和value的map
                Map<String, String> valueKeyMap = new LinkedHashMap<String, String>();//存放value和key的map
                Map<String, String> valueDescMap = new LinkedHashMap<String, String>();//存放value和desc的map
                Map<String, String> descValueMap = new LinkedHashMap<String, String>();//存放desc和value的map
                Map<String, String> descKeyMap = new LinkedHashMap<String, String>();//存放desc和key的map
                //每個內部類-獲取所有屬性(不包括父類的)
                for (Field fd : cls.getDeclaredFields()) {
                    //每個屬性獲取指定的annotation的注解對象
                    ConstantAnnotation ca = fd.getAnnotation(ConstantAnnotation.class);
                    keyValueMap.put(fd.getName(), fd.get(cls).toString());//注解對象空,其值為該field的值
                    valueKeyMap.put(fd.get(cls).toString(),fd.getName());
                    if(ca != null){
                        keyDescMap.put(fd.getName(), ca.value());//注解對象不空,其值為注解對象中的值
                        valueDescMap.put(fd.get(cls).toString(),ca.value());
                        descValueMap.put(ca.value(),fd.get(cls).toString());
                        descKeyMap.put(ca.value(),fd.getName());
                    }
                }
                keyValueMapCons.put(cls.getSimpleName(),keyValueMap);
                keyDescMapCons.put(cls.getSimpleName(),keyDescMap);
                descValueMapCons.put(cls.getSimpleName(),descValueMap);
                descKeyMapCons.put(cls.getSimpleName(),descKeyMap);
                valueDescMapCons.put(cls.getSimpleName(),valueDescMap);
                valueKeyMapCons.put(cls.getSimpleName(),valueKeyMap);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static final String CONSTANT_STRING = "這是一條短消息";

    public static final class TOKEN_FLAG_ONE {

        @ConstantAnnotation("實名")
        public static final String REAL_NAME = "v1";

        @ConstantAnnotation("證書")
        public static final String CRET = "v2";

        @ConstantAnnotation(CONSTANT_STRING)
        public static final String GUR = "v5";//把描述與注解分開

    }
}

 

  好了,有了上面這個類,你就啥都不用愁了,用的時候先拿常量的聲明,再用對應的map,然后指定內部類名稱,想獲取什么,獲取什么。

  打完收工。

  ps:枚舉治理和常量治理結合使用,可能是我們系統開發時的最佳實踐,歡迎有更高效方法的朋友多多指教。

-------------------------------------------里程碑----------------------------------------------

  至此,通過反射、自定義注解來解決系統中一些常見場景的使用問題告一段落,相關文章可參見:

   敏感信息加密處理

   Java中的枚舉治理

-------------------------------------------里程碑----------------------------------------------

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM