Should a class implement a constants-only interface?
Today I looked at the ZipEntry
class and found the following:
public class ZipEntry implements ZipConstants, Cloneable
ZipConstants
does not define any methods - only constants (static final int LOCHDR = 30
)
It then occurred to me that implementing the interface with constants let开发者_C百科s you access those constants directly, as if they were defined in the class itself. For example:
public interface Constants {
static final int CONST = 2;
}
public class implements Constants {
int doSomething(int input) {
return CONST * input;
}
}
Is there another reason not to use this, apart from:
- it is at first confusing where the constant is coming from
- it is considered wrong to use interfaces for constants definition
I'm curious because it is definitely not a very common practice.
Another reasons not to use this:
Since Java 5, there is a "clean" language feature that achieves the same goal: static imports.
Implementing interfaces to use constants is basically a pre-Java-5 hack to simulate static imports.
It is not so rare as you might think, for instance in the static analysis of Parasofts JTest both the rule that constants should be declared in a class
and the rule that constants should be declared in interface
s are present, and it's up to the project to choose between them.
That said, in all my projects I disallow the practice of defining constants in interfaces. Creating a meaningfull class and being explicit about the context of a constant makes code much more readable and thus maintainable than in the case where a developer has to check that constants used in one class are actually the same as those in another class (or not.)
I think that using an interface for shared constants is an example of confusing two different concepts:
- Code reuse
- Subtyping
In my experience using subclassing, or interface implementation simply to prevent the duplication of code leads to problems. Your code becomes more fragile. For example, someone might accidental redefine the constant - especially if your class hierarchy is several classes deep.
It is often better to use composition to keep your code DRY.
Another problem with using inheritance in this way is that generally this type of inheritance forms part of the API of your class. The hierarchy of the class is visible outside of the class. This breaks encapsulation. There is no need for you to expose your use of the constants outside of the class, they are to do with how you have chosen to implement your class and are not part of its API (in your example).
This can lead to horrible backwards compatibility problems. Someone else might come along and write code like this:
public interface Constants {
static final int CONST = 2;
}
public class MyClass implements Constants {
int doSomething(int input) {
return CONST * input;
}
}
public class ThirdPartyClass {
int doSomethingElse(int input) {
return MyClass.CONST + input;
}
}
Now, if you decide you no longer need to use CONST in MyClass you are stuck. Because ThirdPartyClass has create a dependency on CONST being available in MyClass.
You can end up with this. Where MyClass is not using any of the constants in the interface, but still has to implement it.
public interface Constants {
static final int CONST = 2;
}
public class MyClass implements Constants {
int doSomething(int input) {
return input;
}
}
public class ThirdPartyClass {
int doSomethingElse(int input) {
return MyClass.CONST + input;
}
}
In short; never do this!
... because it is considered wrong to use interfaces for constants definition
This is a bad reason not to do something. In fact, it is not a reason at all.
EDIT
Consider this.
- The reason that XXX is bad style is YYY.
- The reason you should do XXX is that it is bad style.
How many substantive reasons are there for not doing XXX? One or two?
If the answer is two, I can make it three, four, five and so on by adding extra tenuous chains of reasons. For example "The reason you should not do XXX is because it is a bad idea." "The reasons it is a bad idea is that it is bad style". And so on. That is plainly silly.
No the real reason for not doing XXX is YYY, and the "Bad style" reason is not a substantive reason. Rather, it is a short cut for saying don't do XXX because of YYY and ZZZ, and any other substantive reasons.
In fact, even the OP's "it is confusing" reason is incompletely stated. WHY is it confusing?
Because an interface is normally a type with classes that implement the interface are subtype. But a constant only interface is not a type in any useful sense, and classes that implement the interface are not subtypes in any useful sense. Ultimately, this is the real reason that implementing constant-only interfaces is called bad style and an "anti-pattern", and it is the main reason that the static imports were added in Java 5.
Nope, this is also known as the "Constant Interface Antipattern". An alternative is writing a concrete class which defines the constants and then use static import.
Class Constants
package util;
public class Constants {
public static final String CONSTANT_STRING = "abc";
private Constants() {
throw new AssertionError();
}
}
Class Test
import static util.Constants.CONSTANT_STRING;
public class Test {
System.out.println(CONSTANT_STRING);
}
See
Wikipedia
for further details.
One of the reasons for not putting your constants in your interface is is that if you expose your interface to a thirdparty they have access to your constants. This may not seem like a bad idea to start off but imagine if you want to change the value of a constant but people are still using an old interface.
When you add something to an interface it has the potential to be set in stone so only add what you want others to see and use.
精彩评论