Page 2 of 2
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.
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.
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.
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.
waste of timeBy Anonymous on September 29, 2009, 10:49 amSorry, but did the author test the code provided? Obviously NOT. First of all it doesn't compile. Secondly, if it did compile, it wouldn't work anyway. SUNDAY, MONDAY...
Reply | Read entire comment
great article but some stuff does not work anymore in 2009?By Anonymous on August 30, 2009, 6:29 amI was trying your second example (Calendar implements Calendar.Parameters), but in Java 5.0 I get: "Cycle detected: the type Foo cannot extend/implement itself or...
Reply | Read entire comment
Great articleBy Anonymous on October 19, 2008, 7:39 amHi! As a Delphi programmer, I really missed its set definition. This is however a great substitute I was looking for. I hated having function parameters declared...
Reply | Read entire comment
View all comments