Five tips for defining classes of constants

Five tips for defining classes of constants

Classes of constants are usually used in the name of removing duplication. For example,

  1. public final class Constants {
  2.  
  3.   private Constants() {}
  4.  
  5.   public static final String CHARSET_NAME_UTF_8 = "UTF-8";
  6. }

In fact, I like the following static methods version more,

  1. public final class Constants {
  2.  
  3.   private Constants() {}
  4.  
  5.   public static String getCharsetNameUTF8() { // see tip 4 below.
  6.     return "UTF-8";
  7.   }
  8. }

The idea is similar to using setters/getters versus direct field access.

Anyway, here are some tips I think are important for defining constant classes based on my observations:

  1. Put only closely related constants into one class so that each class represents one responsibility. The single responsibility principle also applies to these constant classes. This is to avoid unnecessary coupling among the clients of these classes. Enforcing just one central class for all the constants in the application is not going to be a good idea. You just need one location to modify a constant, but there is no need to put all the constants into one class.
  2. Limit the scope to only the minimum. If a constant only makes sense for a class, the constant can be defined as a private member in the same class, not as a public member in another class; If a constant only makes sense for some classes in a package, the constant may be put in a class of constants having the default access level in the same package; if two constants are the same but are isolated in different scopes, think twice before promoting them to a wider scope and deduplicate. The duplication is there for them to evolve independently.
  3. Favor enums over static fields whenever possible. enums are more type-safe than static fields. For example, if a method parameter expects one of three String values, the type of the parameter can be defined as an enum enumerating all the three values. If the values are defined as static fields, the type of the method parameter can only be String, and there is no restriction on the actual value the clients of the method can possibly pass in. In addition, an enum is a full-fledged class where methods can be defined for all or just particular enumerated constants. This is a really nice feature to group all the objects of the same type together in a cohesive way.
  4. Name the constants by their purposes not by their values. For example, the method in the above snippet should really be called something like getDefaultCharsetName() instead of getCharsetNameUTF8(), because whichever method referencing this constant should be coded for any charset name, not implicitly for UTF-8, though it is most likely the default. The naming suggests the abstract purpose of the constant and makes room for future modification, e.g., the default charset name may change over major releases.
  5. Try to reference constants only in glue code. Similar to what has been discussed in the previous item, a class should first be designed to work with any charset name so that it is reusable, then its charset name is set to whatever the constant is when the class is introduced into the current specific use case by glue code. It is the responsibility of the glue code to make sure any charset related classes in the context are using the same default charset name, whereas the classes on their own could even have arbitrary defaults.

In short, all tips are for writing type-safe and loosely-coupled code, for maintainability and reusability.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.

More information about formatting options

To prevent automated spam submissions leave this field empty.