Why the Constant Interface Pattern Should Be Discouraged
Check out this post to learn more about the constant interface pattern and why it should be discouraged.
Join the DZone community and get the full member experience.
Join For FreeIt has been an age old practice to place commonly used constants in an interface, and classes implementing it can directly access those constants without prefixing the interface name.
Advantages of This Practice
Advantage | Remarks |
---|---|
No need to worry about instantiating a class | Constant classes are meant not to be instantiated and hence has a private constructor |
Anything?? | |
Access the constants directly with out prefixing a namespace | Java static import can be used with classes |
Disadvantages of This Practice
Constant Interface Does Not Define a Type
It is considered good practice to segregate the contract (interface defining the type and behavior) from the implementation, and this brings us lots of benefit. Let's consider some examples.
publicclassEmployee implementsPerson {} |
Employee is a Person and defines behavior specific to Person |
publicclassTiger implementsAnimal { } |
Tiger is an Animal and defines behavior specific to Animal |
However, when we write the following, it really does not make sense. Hence, constant interface, by its very nature, does not define any type.
publicclassTiger implementsSessionContants {} |
What does it convey? Tiger is a SessionConstants? |
Run-Time Issues Because of Field Shadowing
publicinterface SessionConstants { String SESSION_NAME = "XYZ"; } publicclassHttpSession implements SessionConstants { privatestaticfinal String SESSION_NAME = "ABC"; publicstaticvoid main(String[] args) { System.out.println(SESSION_NAME); } } |
What you think the sysout would print? Is it desirable? It just works fine with out any warning/error, unlike with Constants class [there would be a warning].Unless a developer checks any implemented interfaces when adding a constant to a class, or does so but makes a typo in the new constant’s name, the value of a constant can be silently changed. |
Namespace Pollution
The named constants appear in the namespace of all implementing classes as well as their sub-classes.
Code Compatibility Issues
If binary code compatibility is required in future releases, the constants interface must remain forever an interface (it cannot be converted into a class), even though it has not been used as an interface in the conventional sense.
Constant Class Approach
The fact that the interface CAN be implemented by an individual, if desired,leaves room for the issues pointed out above. So, it’s best to prevent the ability to implement the interface altogether. Hence, it’s more appropriate to have a final
class that can’t be instantiated (with private constructor) at all.
Bad Practice
public interface SessionConstants {
String COOKIE_NAME = "JSESSIONID";
String WLS_AUTHCOOKIE_PREFIX = "_WL_AUTHCOOKIE_";
String DEFAULT_WLS_AUTHCOOKIE = "_WL_AUTHCOOKIE_JSESSIONID";
}
Preferred approach
public final class SessionConstants {
public static final String COOKIE_NAME = "JSESSIONID";
public static final String WLS_AUTHCOOKIE_PREFIX = "_WL_AUTHCOOKIE_";
public static final String DEFAULT_WLS_AUTHCOOKIE = "_WL_AUTHCOOKIE_JSESSIONID";
private SessionConstants() {
}
}
Advantages of This Approach
- Since the required static memebers are imported statically, the class namespace is not polluted.
- The compiled code has one fewer binary compatibility constraint (that “class implements Constants Interface”).
- Because static imports apply only to the current file (and not the whole class hierarchy), it is easier to discover where each static member is declared.
- Run-time and compile-time semantics are more closely aligned when using static imports instead of constants interfaces.
- If required, static blocks can be declared.
Disadvantages of This Approach
TODO : List out
Constant Interface Pattern and the Rest of the World
Joshua Bloch, in his famous book, Effective Java, talks about it in greater detail:
"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 non final class implements a constant interface, all of its sub classes will have their namespaces polluted by the constants in the interface."
It is indeed a distasteful use of interfaces, since interfaces should deal with the services provided by an object, not its data. As well, the constants used by a class are typically an implementation detail, but placing them in an interface promotes them to the public API of the class. And hence:
Interfaces should only be used to define contracts and not constants!
Published at DZone with permission of Mohammad Nadeem, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments