Constant Interface Anti-Pattern Clarification

That's not quite the pattern. It's more like:

interface Constants {
    final int FOO_1 = 1;
    final int FOO_2 = 2;
}

public class MyClass implements Constants {
    public static void main( String[] args ) {
        System.out.println( FOO_2 ); // compiles OK
    }
}

IMHO, the issue is that MyClass "is not a" Constants. The pattern uses a trick of visibility, but clouds the intention of the class. Further, field shadowing can occur without compiler warnings - this is all the more likely because you see all the fields of the interface, even if you don't use them all.

It's better to import static com.foo.Constants.*; to achieve the same coding convenience, without the misdirection of being a member of Constants.


We can use both class(final with private constructor) and Interface.

However I would prefer class due to the following reasons:

  1. Interface and its implementing classes should have a IS A relationship. Eg: "Cat extends Mammal" means Cat is a Mammal. This doesn't hold true in case we implement constants we use in interfaces.

  2. Interface should define a type.

  3. However now, we can use static import with Interface as well but there is a risk with someone implementing it which will violate "IS A" relationship.

Have a class (with following properties) for constants and make it:

  1. FINAL - so it cannot be inherited by other classes.
  2. Having only a private Constructor :- so it cannot be instantiated.

PS: copying the used example

public final class Constants  // so it cannot be inherited
{

  private Constants() {} // to restrict instantiation

  public static final double PI = 3.14159;
  public static final double PLANCK_CONSTANT = 6.62606896e-34;
}

Now the usage:

import static Constants.PLANCK_CONSTANT;
import static Constants.PI;

public class Calculations
{   
  public double getReducedPlanckConstant()
  {       
        return PLANCK_CONSTANT / ( 2 * PI );   
  }
}

The arguments against the "Constant Interface Pattern" are mainly stylistic. You can use a Constant Interface in Java if it suits your need and in fact the Java libraries include a few of these (though they are considered poor examples that shouldn't be repeated).

The reasons why the Constant Interface is considered by many to be an "anti-pattern" are enumerated in Effective Java, 2nd Ed. Briefly, some of the reasons that this use of interfaces are discouraged include:

  • Namespace pollution. The named constants appear in the namespace of all implementing classes as well as their subclasses.

  • Interfaces should define types. In Java, most of the major types in a project should be represented by interfaces. A constant interface by its nature does not define a type.

  • Noninstantiable classes with import static. Declaring constants as static final fields in a class (rather than an interface) achieves all the same objectives as declaring them in an interface. Doing so does not create namespace pollution by the class. If desired, these constants can be used without the qualifying class name by using the import static declaration.

  • Interfaces should specify behavior. An interface is supposed to define a contract between the interface and implementing classes. Implementing the interface is supposed to say something about what the class can do. Constant interfaces do not follow this pattern.


I realised... the fact that the interface CAN be implemented by an individual if desired, leaves room for the issues pointed out above (i.e. namespace pollution, non-conventional use, exposure through public API ). So it's best to prevent the ability to implement the interface altogether. Hence, it's more appropriate to have a final class with a private constructor so that it can't be instantiated / extended.

public final class Constants
{
      // to restrict instantiation
      private Constants() {}

      public static final double PI = 3.14159;
      public static final double PLANCK_CONSTANT = 6.62606896e-34;
}

... and use that in combination with the import static.

import static Constants.PLANCK_CONSTANT;
import static Constants.PI;

public class Calculations
{   
      public double getReducedPlanckConstant()
      {       
            return PLANCK_CONSTANT / ( 2 * PI );   
      }
}

Tags:

Java