Java Tip 50: On the Parameter Constants pattern

Combine nested interfaces and class constants for flexible design and easy access to constants

Constants normally defined as static members of a class can alternatively be defined in an interface nested within the class. This design pattern allows us to achieve the otherwise conflicting goals, with respect to constants, of decoupling and proper containment. Any client class that makes substantial use of the constants can then implement the interface and use the constants without prefixing the class name. Classes that only need occasional use of the constants can continue to access them in the usual manner. These design patterns for constants are useful for categories of non-private constants such as parameters and prototypes. This design can be augmented with nested classes to provide type safety for parameter constants.

Classes often contain public static final fields (that is, "constants") used as parameters when invoking their methods and constructors. Java's own Calendar class provides a good example of constants for days of the week and months of the year. Take a look at some abbreviated source code for Calendar:

  public abstract class Calendar {
    public static final int SUNDAY = 1;
    public static final int MONDAY = 2;
    // and so on
    public static final int JANUARY = 0;
    public static final int FEBRUARY = 1;
    // and so on
    // constructors, methods, and fields follow
  }

Rather than embedding the constant definitions directly in the class, Java Tip 5:" Java constants," by John D. Mitchell, reminds us that it's possible to group together constants in an interface and implement the interface in a class in order to use unqualified references to the interface's constants. For example, client classes that work with Calendar may have many method invocations of Calendar with many references to the constants. For a given Calendar object, you can change the month with the following statement:

  aCalendar.set( Calendar.MONTH, Calendar.FEBRUARY );

However, if the client class implements an interface that defines the Calendar constants, you could directly refer to the constants without fully qualifying them as follows:

  aCalendar.set( MONTH, FEBRUARY );

This is how the changed design looks:

  public interface CalendarConstants {
    // fields in interface are implicitly public, static, and final
    int SUNDAY = 1;
    int MONDAY = 2;
    // and so on
    int JANUARY = 0;
    int FEBRUARY = 1;
    // and so on
  }
  public abstract class Calendar implements CalendarConstants {
    // constructors, methods, and fields follow
  }

This change to Calendar does not impact preexisting code that refers to the constants -- either code in Calendar itself or code in client classes that refer to the constants fully qualified, which is obviously helpful if you decide to transition a class to this approach. Client classes of Calendar are free to implement the interface and refer to the constants directly. You can also combine client classes that implement the interface with other client classes that fully qualify each constant. An example of such mixed usage can be found in the ScrollPaneConstants interface included in the Swing packages of the Java Foundation Classes (JFC). This coding shortcut comes in handy when you have a client class that works extensively with the constants from a class like Calendar -- though a few references to constants might not justify implementing the interface in a client class.

Now that we have this design, are there additional benefits? If the set of constants evolves to become more widely applicable than its parent class it becomes, in essence, an abstraction. It is independent of the original class, which makes things easier on you. Having already separated the two, you are free to widely implement the decoupled constants' interface. An example of this can be found in the SwingConstants interface included in SwingSet.

Parameter Constant pattern

You may be uncomfortable with an interface like CalendarConstants, where the abstraction of the constants truly depends on a single parent class. There is a solution that keeps the interface but uses nested classes to re-encapsulate the constants in the parent class. Let's call this the Parameter Constant pattern and name the interface Parameters. Returning to our Calendar example, this solution encapsulates the constant interface using a top-level nested interface:

  public abstract class Calendar implements Calendar.Parameters {
    public interface Parameters {
      // Fields in interface are implicitly public, static, and final
      int SUNDAY = 1;
      int MONDAY = 2;
      // and so on
      int JANUARY = 0;
      int FEBRUARY = 1;
      // and so on
    }
    // constructors, methods, and fields follow
  }

At first glance, this nesting may seem strange or non-intuitive, but once you see the idea embodied in the code, it makes sense. Other classes can implement Calendar.Parameters or refer to constants directly such as Calendar.SUNDAY, just as before. This nesting solution has the advantage of placing the interface definition properly within its containing class, the advantage of proper containment. Namespace is not polluted with an unnecessarily top-level interface like CalendarConstants. A good candidate for the Parameter Constant pattern is the ScrollPaneConstants interface and its parent class JScrollPane; both are included in JFC's Swing.

Prototype Constant pattern

If you define class prototypes that are constant in the class itself, you can use a similar approach, which we will call the Prototype Constant pattern. Java uses prototypes with java.awt.Color and java.util.Locale. If you could redesign Java's Color class to use the Prototype Constant pattern, you might do the following:

  public Color implements Color.Prototypes {
    public interface Prototypes {
      // Sorry but JavaSoft did not follow uppercase naming convention.
      Color white = new Color(255, 255, 255);
      Color lightGray = new Color(192, 192, 192);
      // and so on
    }
    // constructors, methods, and fields follow
  }

The final concern is whether our approach can accommodate type safety. The constants in Prototype Constant pattern are, by nature, type safe. We can make our Parameter Constant pattern type safe as well while preserving the interface approach. We build upon our pattern with the insights provided by Philip Bishop in Java Tip 27: " Type safe constants in C++ and Java" in JavaWorld. The following is a simple example that does just that, enforcing type safety for the weekday constants of Calendar by introducing an inner class within our Parameters inner interface:

  public class Calendar implements Calendar.Parameters {
    public interface Parameters {
      WeekDay SUNDAY = new WeekDay(0);
      WeekDay MONDAY = new WeekDay(1);
      WeekDay TUESDAY = new WeekDay(2);
      // and so on...
      final class WeekDay { // final for type safety
        // accessible in containing class Calendar
        private final int weekday;
        // private constructor for type safety but accessible in both
        // containers: Parameters & Calendar
        private WeekDay( int i ) {
          weekday = i;
        }
      }
    }
    // example method signature where parameter is type safe
    public void setWeekday( Parameters.WeekDay weekday ) {
      // method implementation
    }
    // Calendar constructors, methods, and fields follow
  }

By making the type safe class WeekDay an inner class within our nested interface Parameters, we add type safety to our earlier accomplishments of proper containment, uncluttered namespace, and easy access constants.

Note that the javadoc utility shipped with JDK 1.1 has trouble with inner classes, but the good news is that javadoc with JDK 1.2 corrects the problem. You can download and use just the javadoc from JDK 1.2 Beta 2 (or later) even though your development platform remains JDK 1.1.

Conclusion

Like any other design technique, use these patterns with good judgement. If a class merely has one parameter with two or three associated constants, it may not be worthwhile to apply the Parameter Constant pattern. Recall that you can inherit multiple interfaces in either client classes or sub-interfaces. The inheritance features combined with the patterns we have developed here leaves you with tremendous flexibility to design your class constants for greatest convenience while keeping them where they belong.

Jon Steelman has been a software consultant for 10 years. Since early 1996, his passion in programming languages has been Java. His interests also include design patterns and object-oriented analysis and design. He was the first person to become a Sun Certified Java Programmer when Sun started the program in late '96. Jon is a Georgia Tech graduate in electrical engineering and lives in Atlanta.

Learn more about this topic

Join the discussion
Be the first to comment on this article. Our Commenting Policies