Greetings, in my workplace I've noticed quite a few interfaces containing only constants (dozens of them), having read (many times): Effective Java: Programming Language Guide, by Joshua Bloch, (rule 17 states: Use interfaces only to define types) I sent out a note stating that we should stay away from this practice, I received a reply back that there were good reasons for using interfaces containing only constants (see below), however, I can think of several ways around the stated reply (just takes a little work).
Question: am I wrong about this, or are there good reasons for taking the easy way out?
(Reply received back) I agree that we should not abuse the usage of the constants interface - especially creating a giant interface to capture all the constants is not a good practice (breaks the encapsulation). But there is merit using constant interface rather than a constant class or enum.
In my opinion, there are a few examples of using constants interface. - The name of the attributes/parameters in HttpServletRequest/HttpServletSession so that multiple Actions, Servlets and JSPs are to use the same value (avoid typo). - The ActionForward names used to match the struts-config.xml - DAO DB column constants
By defining them as constants, you can take advantage of multiple inheritance of interfaces to access constants defined in multiple base interfaces. Although the constants are not type safe, they do limit the values used in different classes.
Originally posted by Tom Bigbee: By defining them as constants, you can take advantage of multiple inheritance of interfaces to access constants defined in multiple base interfaces. Although the constants are not type safe, they do limit the values used in different classes.
This is called the Constant Interface Antipattern according to Effective Java.
The problem with this is that if you are implementing an interface like that, you are introducing all the constants in the interface into the public API of your class. That's a bad thing. The public API of your class should be as small as possible if you want to write maintainable software; it should certainly not contain a whole lot of constants that are only needed for the internals of the class.
To get rid of this problem static import was added to Java 5. So, you should use static import instead.
Unfortunately this anti-pattern has been used in several places in the Java API itself. That doesn't justify its use in your own code...
Did you show the people you've e-mailed with your Effective Java book? [ June 20, 2007: Message edited by: Jesper Young ]
I think it's helpful to pay attention to who exactly needs to use these constants. Bloch's arguments apply to classes that use constants internally. They don't really apply to classes that intentionally make those constants available to clients, as part of their own APIs.
For example, consider WindowConstants. The three classes that implement this are JDialog, JFrame, and JInternalFrame. They all have some common behavior, setDefaultCloseOperation(). This method really should have been defined in the same interface - let's call it ClosableWindow:
Here the constants are intended to be used by clients of JDialog, JFrame, and JInternalFrame - and it makes perfect sense for those clients to see the constants as part of the API. However it would not make sense for those clients to implement this interface just so they can use the constants. If my class JimsTetrisGame uses a JFrame, that's fine. But people who use my class don't need to read about DISPOSE_ON_CLOSE etc, because it's not something they need to call in code in order to use my class. So I shouldn't implement WindowConstants or ClosableWindow just to make my life a tiny bit easier inside the JimsTetrisGame class, because that would unnecessarily affect the public API of my class.
Here we see that defining the method setDefaultCloseOperation() inside ClosableWindow is helpful. Because If I'm writing JimsTetrisGame and I want to implement WindowConstants just for my own convenience, nothing's stopping me. (Other than the fact I am aware this is an antipattern.) But with ClosableWindow, it's different, because I can't implement that without implementing the method setDefaultClosableOperation(). And when I start to do that, I realize that this method isn't something that clients of my class need - therefore it shouldn't be part of my public API.
Note that Bloch doesn't say you shouldnever put constants in interfaces. He recommends against defining interfaces just to make internally-used constants more accessible. But if the constants are intentionally part of the API, and if the interface also defines one or more methods that use those constants, that's a different story, much more justifiable.
Note that for most of the examples I can think of, it would be preferable to use an enum to define the list of values that are used by a method. Or prior to JDK 5, you could use the type-safe enumeration pattern. But this wasn't known - at least, not widely known - at the time many standard library classes were designed. A more modern version of ClosableWindow would be:
I suspect that for many of the examples Tom's co-worker is thinking of, putting constants in interfaces is similarly justifiable - clients do need to use them. Together with methods that take those constants as parameters. And since enums are not available (JDK 1.4), the type-safe enumeration pattern is worth considering. [ June 21, 2007: Message edited by: Jim Yingst ]
"I'm not back." - Bill Harding, Twister
Joined: Sep 16, 2002
Thanks, very much for your comments, they were very imformative