|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
n "Constants" (JavaWorld, March 30, 2001), I wrote, "I'd be interested to hear how others declare their constants and why. I can post your responses
in a future Q&A." Well, here are some reader responses.
It turns out that using an interface to declare constants may not be the best practice after all. In fact, using interfaces in this way may be downright nasty. Why? Interfaces should only be used to define types; any other use is an abuse. Using an interface causes internal details -- such as constants -- to leak into the class' public API. Once something becomes part of the public API, you can never get rid of it. Thanks to Josh Bloch for smacking me upside the head and setting me straight.
Josh pointed me to his excellent article, "Substitutes for Missing C Constructs," (java.sun.com), which describes a design pattern for creating design patterns in Java. Such a pattern works very nicely for declaring XML tags. Be sure to look out for Josh's upcoming book, Effective Java Programming Language Guide (Addison-Wesley, June 2001).
Originally, I advocated using an interface. Consider the following XML markup:.
<Recipes>
<Recipe>
<Ingredient>
<Ingredient>
</Recipe>
</Recipes>
I would have created the following interface:
public interface RecipeMarkup {
public final static String RECIPES_TAG = "Recipes";
public final static String RECIPE_TAG = "Recipe";
public final static String INGREDIENT_TAG = "Ingredient";
}
By following the pattern, I can create the following class instead:
public class Markup {
private final String tag;
// make protected so we can override if new tags are added
protected Markup(String tag) { this.tag = tag; }
public String toString() { return tag; }
// might also add a compare(String) method to simplify comparison
// such as when we want to handle SAX events
public static final Markup RECIPES =
new Markup("Recipes");
public static final Markup RECIPE =
new Markup("Recipe");
public static final Markup INGREDIENT =
new Ingredient("Ingredient");
}
By adding a compare(String) method, we can simplify tag comparison. For example, if you use SAX, you have to do a string comparison to figure out what
tag you're dealing with in the event. This pattern is great for enumerations; the XML markup should be an enum. However, there
are some other ways to define pure run-of-the-mill constants.
Jay Baker sent me a good suggestion. I'll let him say it in his own words:
I prefer the use of an abstract class with public static final constants for most implementations. This is just as easy to implement. Whether an interface or a class, one must still define
the interface or class and put the constants in there. The best reason to use this method is that it more closely matches
the design concept. Using an abstract class is an implementation of the "uses" association that is really what you want with
constants. Implementing an interface implies something that is not really there in the case of constants.
Josh Bloch made a similar suggestion:
I'd still recommend against the use of "constant interfaces." Interfaces should be used to define types; any other use constitutes abuse. If the constants are subservient to some other class or interface, put them into it. If not, make a "utility class" containing the constants:
public class RecipeMarkup { private RecipeMarkup() { } // Prevents instantiation public static final String RECIPES_TAG = "Recipes"; public static final String RECIPE_TAG = "Recipe"; public static final String INGREDIENT_TAG = "Ingredient"; }
Note that I've done three things to your interface: First, I turned it into a class. Second, I added a private constructor to suppress the default constructor, thus guaranteeing noninstantiability. Third, I made all the constants final. Your constants weren't final, so a malicious or confused client could change them.