摘要:相信很多同窗在見過千奇百怪的常量類以後都有這樣的疑問——怎麼管理這些常量類?
本文分享自華爲雲社區《編程實戰:如何管理代碼裏的常量》,原文做者:技術火炬手。程序員
相信很多同窗在見過千奇百怪的常量類以後都有這樣的疑問——怎麼管理這些常量類,但同時又以爲這個好像不是很重要,怎麼管理都能用的樣子,不就是個常量嘛,今天咱們就把這個問題打開來看看。spring
從事Web開發,有個繞不開的常量就是HTTP的狀態碼,不如以此爲起點apache
①使用枚舉編程
public enum HttpStatus { CONTINUE(100, "Continue"), SWITCHING_PROTOCOLS(101, "Switching Protocols"), PROCESSING(102, "Processing"), CHECKPOINT(103, "Checkpoint"), OK(200, "OK"), CREATED(201, "Created"), ACCEPTED(202, "Accepted"), NON_AUTHORITATIVE_INFORMATION(203, "Non-Authoritative Information"), NO_CONTENT(204, "No Content"), ...
②類中定義常量segmentfault
public class HttpStatus { public static final int CONTINUE_100 = 100; public static final int SWITCHING_PROTOCOLS_101 = 101; public static final int PROCESSING_102 = 102; public static final int OK_200 = 200; public static final int CREATED_201 = 201; public static final int ACCEPTED_202 = 202; public static final int NON_AUTHORITATIVE_INFORMATION_203 = 203; public static final int NO_CONTENT_204 = 204; ...
③final類中定義常量框架
public final class HttpStatus { public static final int SC_INFORMATIONAL = 100; public static final int SC_CONTINUE = 100; public static final int SC_SWITCHING_PROTOCOLS = 101; public static final int SC_PROCESSING = 102; public static final int SC_EARLY_HINTS = 103; public static final int SC_SUCCESS = 200; public static final int SC_OK = 200; public static final int SC_CREATED = 201; public static final int SC_ACCEPTED = 202; public static final int SC_NON_AUTHORITATIVE_INFORMATION = 203; public static final int SC_NO_CONTENT = 204; ...
以上都是在經常使用開源框架中的定義,在業務中還曾見過一種用法,是eclipse
④在接口中定義常量函數
public interface HttpStatus { public static final int CONTINUE_100 = 100; public static final int SWITCHING_PROTOCOLS_101 = 101; public static final int PROCESSING_102 = 102; public static final int OK_200 = 200; public static final int CREATED_201 = 201; public static final int ACCEPTED_202 = 202; public static final int NON_AUTHORITATIVE_INFORMATION_203 = 203; public static final int NO_CONTENT_204 = 204; ...
這種接口被稱爲常量接口,不過在《Effective Java》中的「接口只用於定義類型」這條建議中,特別批評了這種常量接口,認爲「常量接口模式是對接口的不良使用」。原文敘述以下:this
The constant interface pattern is a poor use of interfaces. That a class uses some constants internally is an implementation detail. Implementing a constant interface causes this implementation detail to leak into the class’s exported API. It is of no consequence to the users of a class that the class implements a constant interface. In fact, it may even confuse them. Worse, it represents a commitment: if in a future release the class is modified so that it no longer needs to use the constants, it still must implement the interface to ensure binary compatibility. If a nonfinal class implements a constant interface, all of its subclasses will have their namespaces polluted by the constants in the interface.
常量接口模式是使用接口的糟糕方式。類內部會使用一些常量,這是實現細節。然而,實現常量接口會致使這個實現細節泄漏到類的導出 API 中。對於類的用戶來講,類實現一個常量接口沒有什麼價值。事實上,這甚至會讓他們感到困惑。更糟糕的是,它表明了一種承諾:若是在未來的版本中修改了類,使其再也不須要使用常量,那麼它仍然必須實現接口以確保二進制兼容性。若是一個非 final 類實現了一個常量接口,那麼它的全部子類的命名空間都會被接口中的常量所污染。
考慮到常量類不該該被繼承,使用final要比沒有合適。
此外考慮到常量類應該不須要被實例化,將構造函數設置爲private也是種額外的保護。spa
綜上,使用枚舉和final常量類就是首選了,那麼這二者之間又如何抉擇呢?咱們仍是能從《Effective Java》獲得有效的建議,第34條中就是在建議咱們用枚舉替代int常量。
雖然枚舉是首選,可是常量類不會消失,常量不僅是int常量,字符串常量也是平常開發中避不開的,並且有些時候咱們仍是會以爲常量更爲便捷。那該如何管理這些常量呢?
把程序中全部用到的常量,都集中放到一個Constants類中。這樣作會有一些缺點,
做爲職場新人的時候,我常乾的一件事情就是重複定義常量,由於我不知作別人是否認義過,在哪裏定義過,與其要翻遍整個代碼庫去找這個常量,本身定義一個顯得方便的多。
直到有一天我須要去修改一個常量的定義,前面欠下的債就須要還了。重複代碼最大的問題就是,當你須要去修改或者維護那段重複的代碼的時候,你須要去修改每一處,若是有遺漏,那就是bug了。重複常量也是如此。
一個思路是按功能維度,去定義常量,一個常量類只跟某一功能相關。
如MySQLConstants、RedisConstants。
但這個有個很虛的概念,就是功能,一個功能可大可小,範疇能夠是某一個類,也能夠是一整個模塊,這裏沒有定論,依賴的就是程序員聰明的頭腦和豐富的經驗了。
另一種思路就是不單獨設計常量類,常量在哪一個類裏面使用,就把常量定義到這個類中。
好比在RedisClient和RedisConfig中都用到了以前RedisConstants中的常量,能夠將其分別定義在RedisClient和RedisConfig中。
但這樣作有個明顯的問題就是,若是多個類用到了同一個常量,若是各自定義就形成了重複,若是定義一份聲明爲public,就會形成兩個類之間的依賴。這樣來看,在沒有複用訴求的狀況下,就地定義才比較可取。
上述兩種方式都沒有完整的解決咱們的疑惑,考慮將上述兩種方式結合起來,能夠獲得一種按層次定義複用的方式。