49

I am writing a set of junit test classes in Java. There are several constants, for example strings that I will need in different test classes. I am thinking about an interface that defines them and every test class would implement it.

The benefits I see there are:

  • easy access to constants: MY_CONSTANT instead of ThatClass.MY_CONSTANT
  • each constant defined only once

Is this approach rather a good or bad practice? I feel like doing so is a little like abusing the concept of interfaces.

You can answer generally about interfaces/constants, but also about unit tests if there is something special about it.

1
  • The answer for "It is a bad practice to have an interface define X?", being X anything that isn't "method signatures", is almost always surely "Yes".
    – T. Sar
    Commented Jun 1, 2017 at 20:11

7 Answers 7

90

Joshua Bloch advises against this in his book titled Effective Java:

That a class uses some constants internally is an implementation detail. Implementing a constant interface causes this implementation detail to leak into the classes' exported API. It is of no consequence to the users of a class that the class implements a constant interface. In fact, it may even confuse them. Worse, it represents a commitment: if in a future release the class is modified so that it no longer needs to use the constants, it still must implement the interface to ensure binary compatibility.

You can get the same effect with a normal class that defines the constants, and then use import static com.example.Constants.*;

0
17

In our case we're doing this because the values of the constants represent a contract for end states that a service implementation is required to provide. Putting these constants in the interface specifies the end states as a part of the contract, and if any implementation of the interface didn't use them it would not be doing its job.

SOMETIMES constants are implementation details. SOMETIMES they are not. As usual, an engineer needs to use his brain to decide what to do, and not rely on a sweeping pattern or practice.

7

I don't think it's a good thing to have interfaces only for constants.

But if an interface that defines behavior (methods implementing classes should implement), has constants, it's OK. If it "leaks some implementor's detail" into the API, it's because that's the way it should be. They are also leaking that the implementor implements .foo() and .bar() methods.

Take for example the java.awt.Transparency interface. It has OPAQUE, BITMASK and TRANSLUCENT constants but also has .getTransparency() method.

If the designer put those constants there it's because he/she thought that would be stable enough to be part of the interface, as .getTransparency() is.

2

Think it is a viewpoint mostly popular in places where design by contract is prevailent.
Interfaces are contracts. Placing constants in interfaces means every class that abides by the contract agrees to the value/concept identified by the constant.

4
  • 1
    interfaces are public contracts. Constant VALUES are private concerns, the public interface should at most expose their names. That's best left to an abstract class.
    – jwenting
    Commented Feb 24, 2011 at 8:00
  • Cases in point: javax.naming.Context, javax.ims.Session, and hundreds of such interfaces...
    – CMR
    Commented Feb 24, 2011 at 12:02
  • 2
    @jwenting Also, could a public interface "at most expose their names", without exposing the values?
    – CMR
    Commented Feb 24, 2011 at 13:17
  • that'd depend on the programming language I guess. In case of Java, no.
    – jwenting
    Commented Aug 1, 2014 at 15:05
2

A company I worked at made heavy use of interface-imported1 constants. I don't feel any harm came of it.

The question you should be asking yourself is, how important is namespacing to you? In the case of constants, that's really all a class acts as. If you have thousands of constants, you may not want all of those constants always available.

The cool thing about interfaces is it gives you the benefit of working either way - bring in all the namespaces you need, or none of them (and access them explicitly, with MyInterface.CONSTANT). Pretty much the same thing as import static MyInterface.*, but a little bit more obvious.


1: If you're not familiar with Java, I don't mean the import keyword, I just mean brought in via implements MyConstantsInterface

1

I come from a background that is mostly influenced primarily by the 'Ada way' and the '.Net way.' I would say no, that it is probably not best to declare constants within interfaces. It is technically not allowed in c#.

The reason I say no is that a an interface is a form of contract that defines behavior, not state or structure. A constant implies some kind of state (primitive), or an aspect of state (composite or aggregate).

I can appreciate the urge to make defaults and predefined values available to everyone who implements the interface, but perhaps the default state would be better described in an abstract or value object or template , where the defaults would have at least minimal context.

For a more technical guide: download.oracle.com/javase/1.5.0/docs/guide/language/static-import.html

2
  • Adding more links referring to Static Import (1.5): 1. Wikipedia 2. Oracle Docs referencing @Justinc
    – Abhijeet
    Commented Nov 12, 2015 at 3:10
  • 1
    So when should you use static import? Very sparingly! Only use it when you'd otherwise be tempted to declare local copies of constants, or to abuse inheritance (the Constant Interface Antipattern). In other words, use it when you require frequent access to static members from one or two classes. If you overuse the static import feature, it can make your program unreadable and unmaintainable, polluting its namespace with all the static members you import. Reference from Oracle Docs
    – Abhijeet
    Commented Nov 12, 2015 at 3:16
-1

No it's not a general bad practise.

The point is that constants as any other artefact should be introduced under the rules of minimal visibility and proper abstraction level.

Using syntax only because you can is the real problem.

Not the answer you're looking for? Browse other questions tagged or ask your own question.