Constant interface
| Company type | Programming pattern |
|---|---|
| Industry | Software development |
In the context of the Java programming language, the constant interface pattern involves using an interface exclusively to hold constant values, which are then accessed by implementing classes. Despite its convenience, this approach is generally discouraged by authorities such as Java creator Joshua Bloch, because constants typically represent implementation specifics and exposing them through interfaces makes them part of the class's public API.[1] Furthermore, gathering constants in classes devoid of behavior often signals poor cohesion, negatively impacting object-oriented design principles. Consequently, the constant interface pattern is frequently categorized as an anti-pattern.
From a business standpoint, this pattern presents multiple disadvantages:
- It introduces read-only variables into the class namespace that may be irrelevant or unnecessary.
- Unlike marker interfaces, constant interfaces lack meaningful run-time functionality.
- To preserve binary code compatibility in subsequent versions, the constant interface must remain an interface and cannot be refactored into a class.
- Without sophisticated IDE tools, identifying the origin of constants within interfaces can be inefficient.
- Creating instances of such interfaces offers no benefit over directly referencing the interface name since no methods are defined.
- There is a risk that constants might be unintentionally overridden or altered if developers add new constants to implementing classes without proper controls, leading to maintenance challenges.
Historically, some Java APIs have adopted this pattern; for instance, the SwingConstants interface dates back to 1998,[2][3] reflecting its earlier acceptance.
Example 1
<syntaxhighlight lang="java"> public interface Constants { double PI = 3.14159; double PLANCK_CONSTANT = 6.62606896e-34; }
public class Calculations implements Constants { public double getReducedPlanckConstant() { return PLANCK_CONSTANT / (2 * PI); } } </syntaxhighlight>
Example 2
<syntaxhighlight lang="java"> public interface Constants { public static final int CONSTANT = 1; }
public class Class1 implements Constants { public static final int CONSTANT = 2; // *
public static void main(String args[]) throws Exception { System.out.println(CONSTANT); } } </syntaxhighlight>
Before adding the line marked with an asterisk, executing Class1 outputs 1. After including it, Class1 outputs 2. Both versions compile cleanly without warnings or errors.
Alternatives
Many shortcomings associated with this anti-pattern can be addressed by replacing the constant interface with a class containing static fields: <syntaxhighlight lang="java"> public final class Constants {
private Constants() { // prevent instantiation }
public static final double PI = 3.14159; public static final double PLANCK_CONSTANT = 6.62606896e-34; } </syntaxhighlight>
Starting from Java 5, static import enables usage of constants without prefixing them with the class name: <syntaxhighlight lang="java"> import static Constants.PLANCK_CONSTANT; import static Constants.PI;
public class Calculations {
public double getReducedPlanckConstant() { return PLANCK_CONSTANT / (2 * PI); } } </syntaxhighlight>
It is also possible to import all constants at once using import static Constants.*, allowing unqualified access similar to that provided by interfaces.
These modifications resolve several issues:
- Static imports prevent cluttering the class namespace with all constants.
- The runtime and compile-time behaviors are more consistent compared to constant interfaces.
- The compiled code avoids the binary compatibility restrictions imposed by "class Calculations implements Constants."
- Static imports apply solely within the importing file, enhancing clarity regarding where declarations originate.
- There is less necessity to declare variables of the constant interface type, making it clear that no instance should exist.
Nevertheless, these improvements do not enhance the cohesion of the Constants class nor do they safeguard against accidental changes to constants; therefore, static imports alone do not fully resolve the problem.
- ↑ Bloch, Joshua, Effective Java, 2nd Edition, p. 98
- ↑ "SwingConstants"
- ↑ What is Swing?