Converting constants-only interfaces to abstract classes

R

Rhino

I was advised in another thread to avoid creating interfaces that contained
only constants; I was told that abstract classes were a better choice for
something that only contains constants. I was also given the reasons why it
is bad to make an interface contain only constants and I am satisfied that
those are good reasons.

I started to convert two existing constants interfaces to abstract classes
and immediately got into trouble. I changed my first interface,
ResumeConstants, to an abstract class, and that was no problem. But now, the
compiler is complaining in all of the classes that contain "implements
ResumeConstants"; the messages are quite reasonable: you can't implement an
abstract class.

I realize that you usually _extend_ abtract classes but many of the classes
that used to implement ResumeConstants are already extending other classes,
like JApplet or ResumeFileCreator.

How do I handle those cases? I'm afraid my OO theory isn't too strong so
forgive me if the answer seems obvious to you; it isn't obvious to _me_
 
S

Stefan Ram

Rhino said:
How do I handle those cases? I'm afraid my OO theory isn't too
strong so forgive me if the answer seems obvious to you; it
isn't obvious to _me_

Here is an example of a class using two constant variables
from other classes:

class Math { final static double pi = java.lang.Math.atan( -1 )* -4; }
class Phys { final static double c_m_s = 299792458; }
public class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( Math.pi );
java.lang.System.out.println( Phys.c_m_s ); }}

"import static" can be used to get rid of the class prefix:

import static java.lang.Math.PI;
import static java.awt.Color.RED;
public class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( PI );
java.lang.System.out.println( RED ); }}

In Java, only interfaces have constants; classes have constant
variables.
 
D

Daniel Dyer

In Java, only interfaces have constants; classes have constant
variables.

Isn't that an oxymoron? It's like the sticker on my old Sony VAIO that
informed me of the available "optional essentials".

Dan.
 
A

Andrew McDonagh

Rhino said:
I was advised in another thread to avoid creating interfaces that contained
only constants; I was told that abstract classes were a better choice for
something that only contains constants. I was also given the reasons why it
is bad to make an interface contain only constants and I am satisfied that
those are good reasons.

I started to convert two existing constants interfaces to abstract classes
and immediately got into trouble. I changed my first interface,
ResumeConstants, to an abstract class, and that was no problem. But now, the
compiler is complaining in all of the classes that contain "implements
ResumeConstants"; the messages are quite reasonable: you can't implement an
abstract class.

I realize that you usually _extend_ abtract classes but many of the classes
that used to implement ResumeConstants are already extending other classes,
like JApplet or ResumeFileCreator.

How do I handle those cases? I'm afraid my OO theory isn't too strong so
forgive me if the answer seems obvious to you; it isn't obvious to _me_

before you would have done something like.....

public interface ResumeConstants {
public String HEADER = "Header";
}


public class ResumeWriter implements ResumeConstants {

public void writeResume() {
System.out.println(HEADER);
}

}



Which you now know is not a good use of interfaces - its even thought of
as a anti-pattern.

So what to do....convert the interface into a class (as you have done),
and make the constants 'static'.


public class ResumeConstants {
public static final String HEADER = "Header";
}


Now to make use of it...

public class ResumeWriter {

public void writeResume() {
System.out.println(ResumeConstants.HEADER);
}

}


By making the constants static, it saves you having to instantiate the
ResumeConstants class in order to use its constants....e.g.

public class ResumeWriter {

public void writeResume() {
ResumeConstants rc = new ResumeConstants();
System.out.println( rc.HEADER );
}

}

Now this business about making the constants class an abstract class....

If you try and use Inheritance you will always run into this type of
problem. This situation only ever calls for Delegation, not Inheritance.

In fact your designs will generally be much better if you 'favor
Delegation Over Inheritance' (nice and google-able term)

Even with Delegation, there's really only one valid reason for going the
Abstract class route, with these constants classes.... its to make it
difficult to instantiate the class like I just did above. However,
making it Abstract merely prevents some one 'newing' the class directly,
it does not stop them creating a derived class and newing that instead.
A better approach for be to make the default constructor 'private'.

As in...


public class ResumeConstants {
public static final String HEADER = "Header";

private ResumeConstants() {}
}


We sometimes do this if we think its a good thing to prevent this, but
there's always cases where we don't want to do this.

Going this route can actually leave you in as much trouble as having the
interface constants. For example, say your constants were just that,
constants, but then we have a new business requirement that says we need
two or more different sets of constants, depending upon the user's
locale. We'd be buggered if we used the approach above.

Instead, what we'd want to do it not directly access the constants
values, we want to get them via access methods (getters), but we'd want
to instantiate different ResumeUserLocaleConstants classes depending
upon locale, then use them in a polymorphic manner.

public interface UserLocaleDependantConstants {
public String getHeader();
public String getFooter();
...
}

public class UkUserConstants implements UserLocaleDependantConstants {
// ... load UK values for the user constants...
}

public class USAUserConstants implements UserLocaleDependantConstants {
// ... load USA values for the user constants...
}

public class FrenchUserConstants implements UserLocaleDependantConstants {
// ... load French values for the user constants...
}

....

so we still have constants, just a different set are created at
application start up, or read from a server, or file, or....

HTH

Andrew
 
S

Stefan Ram

Daniel Dyer said:
Isn't that an oxymoron? It's like the sticker on my old Sony
VAIO that informed me of the available "optional essentials".

A variable is a storage location and has an associated type.
A final variable may only be assigned to once.

The JLS seems to use the term "constant" when referring to
enum constants or fields of interfaces only.
 
T

Tony Morris

Whatever the case, it is wrong.
A variable is a storage location and has an associated type.
A final variable may only be assigned to once.

Not quite - a final is "write once" only if it is a field.
A final local may be "write never" - definite assignment rules mandate that
it has been "definitely written once" upon first use.
The JLS seems to use the term "constant" when referring to
enum constants or fields of interfaces only.

Where?

When a final is not a constant
http://jqa.tmorris.net/GetQAndA.action?qids=13
 
T

Tony Morris

Rhino said:
I was advised in another thread to avoid creating interfaces that contained
only constants; I was told that abstract classes were a better choice for
something that only contains constants.

You have been misled.
Assuming your true objective is not fulfilled by an enumeration, and indeed
requires you to write code that uses constant expressions, the optimal
solution is the use of a final class - which is mutually exclusive from an
abstract class and is quite the opposite. The class should declare a private
constructor with a throws clause that specifies a single unchecked exception
(such as java.lang.UnsupportedOperationException). The constructor should
explicitly throw this exception as its only statement. Your constants should
be specified using public static final fields, which indeed should be
constants - and not finals, which is a common cause of confusion.
 
S

Stefan Ram

Tony Morris said:
Not quite - a final is "write once" only if it is a field.

Both sentences are quotations from the
Java Language Specification, Third Edition.

I was referring to the noun "constant" - not the adjective.
The domain of my assertion is not localized in the Java
Language Specification, Third Edition: One has to find every
usage of the noun "constant" in the Java Language
Specification, Third Edition and then classify its meaning.

I have gained the impression that this will always refer to
interface or enumeration constants, but I will recognize any
counter-example, when someone points to it.
 
R

Roedy Green

Isn't that an oxymoron? It's like the sticker on my old Sony VAIO that
informed me of the available "optional essentials".

do interface constants have to be evaluated at compile time?
or can they be postponed till load time?
 
S

Stefan Ram

Roedy Green said:
do interface constants have to be evaluated at compile time?
or can they be postponed till load time?

»Every field in the body of an interface must have an
initialization expression, which need not be a constant
expression. The variable initializer is evaluated and the
assignment performed exactly once, when the interface is
initialized.«

Java Language Specification, Third Edition, 9.3.1,
 
T

Tony Morris

Stefan Ram said:
Both sentences are quotations from the
Java Language Specification, Third Edition.

The JLS is full of contradictory text. I do not envy anyone who chooses to
implement such a specification.
It is for this reason, and many more, that I have resigned from my current
position.
Last day this Friday!!! yippeeeee!!!
In case you can't tell, I can't wait :)
 
A

Adam Maass

Rhino said:
I was advised in another thread to avoid creating interfaces that contained
only constants; I was told that abstract classes were a better choice for
something that only contains constants. I was also given the reasons why it
is bad to make an interface contain only constants and I am satisfied that
those are good reasons.

I started to convert two existing constants interfaces to abstract classes
and immediately got into trouble. I changed my first interface,
ResumeConstants, to an abstract class, and that was no problem. But now,
the compiler is complaining in all of the classes that contain "implements
ResumeConstants"; the messages are quite reasonable: you can't implement
an abstract class.

I realize that you usually _extend_ abtract classes but many of the
classes that used to implement ResumeConstants are already extending other
classes, like JApplet or ResumeFileCreator.

How do I handle those cases? I'm afraid my OO theory isn't too strong so
forgive me if the answer seems obvious to you; it isn't obvious to _me_

Implementing an interface to get the constants it defines is considered an
anti-pattern; you have at least one (and possibly many) instances of this
anti-pattern in your code. The required change is to:

1) Remove the "implements ResumeConstants" phrase from the class
declaration;
2) Qualify all references to constants:

where before you had:

A

you now need:

ResumeConstants.A




Hope that helps...
 
C

Chris Uppal

Stefan said:
»Every field in the body of an interface must have an
initialization expression, which need not be a constant
expression. The variable initializer is evaluated and the
assignment performed exactly once, when the interface is
initialized.«

But note that interface constants, being final, will normally be evaluated by
the compiler and hard-wired into the code that uses them. The exceptions are
constants that are not initialised to a compile-time constant-valued expression
of numerical, boolean, or String type.

-- chris
 
C

Chris Uppal

Rhino said:
I was advised in another thread to avoid creating interfaces that
contained only constants;

So far so good ;-)

I was told that abstract classes were a better
choice for something that only contains constants.

It may, and in my experience nearly always does, make more sense to attach the
constants to the class to which they pertain. I.e. while there can be reasons
to create a class just to hold constants, it is rarely necessary or desirable.
(And, frankly, in those rare cases it makes no difference at all whether you
use an abstract class or an interface -- it's a hack either way -- just don't
make the mistake of trying to inherit ("extends" or "implements") the class
containing the constants. Use the constants, don't inherit them).

Classes that are clients of other classes can use the constants defined by the
other classes if those constants are public (which they should be /if/ they
are intended for use by other classes).

-- chris
 
Z

zero

Assuming your true objective is not fulfilled by an enumeration, and
indeed requires you to write code that uses constant expressions, the
optimal solution is the use of a final class - which is mutually
exclusive from an abstract class and is quite the opposite.

A final class may indeed be better for this purpose. Note that in my
original post about this, I said "Use a non-instantiable (for example
abstract) and preferably final class"

I completely disagree with the fact that abstract and final are mutually
exclusive. While it is true that the concepts are eachother's opposites
(abstract classes are meant to be extended, final classes can't be), it is
perfectly possible to have code like this:

public abstract class AbstractFinal
{
private AbstractFinal() {}

// a bunch of constants and perhaps static methods
// never call the AbstractFinal constructor
}

While this class is not declared as final, it is effectively final because
it cannot be extended. This can be made even more clear if the constructor
throws an InstantiationException.

Yes this is an improper use of abstract classes, and the same could (and
maybe should) be done just by having a final class with a private
constructor. However I don't see the above code ever leading to problems.
 
C

Chris Uppal

Tony said:
The JLS is full of contradictory text. I do not envy anyone who
chooses to implement such a specification.
It is for this reason, and many more, that I have resigned from my
current position.
Last day this Friday!!! yippeeeee!!!
In case you can't tell, I can't wait :)

Congrats !

Are you shunning the JLS ? Java ? Programming ? I'm just curious:
please ignore this question if you don't care for it.

-- chris
 
C

Chris Uppal

Andrew said:
Even with Delegation, there's really only one valid reason for going the
Abstract class route, with these constants classes.... its to make it
difficult to instantiate the class like I just did above. However,
making it Abstract merely prevents some one 'newing' the class directly,
it does not stop them creating a derived class and newing that instead.

Granting the (unlikely, IMO, but not impossible) hypothesis that a
constants-only class is required, I find myself asking:

a) Why would anyone want to instantiate it ?

b) If someone did, why would one want to prevent them from doing so ?

c) If this /is/ an issue, then what of Thomas Hawtin's point that an
interface will achieve exactly the same thing with less clutter and
semantic noise ?

Going this route can actually leave you in as much trouble as having the
interface constants. For example, say your constants were just that,
constants, but then we have a new business requirement that says we need
two or more different sets of constants, depending upon the user's
locale. We'd be buggered if we used the approach above.

Agreed. I just wanted to point out that if there /isn't/ an [anticipated]
business requirement to do so, then this kind of messing around is
over-engineering. No criticism of your point intended, but I suspect that
Rhino's getting a bit confused with the range of "best-practise" that's being
recommended ;-)

-- chris
 
R

Roedy Green

It may, and in my experience nearly always does, make more sense to attach the
constants to the class to which they pertain.

If you do have a Configure class where configuring constants are
concentrated for tweaking, you can get the interface-like ability to
access the fields without qualification if you use the import static
feature of JDK 1.5.

The advantage of using a Configure class over a properties file, is
you can do computation if need be to decide the various parameters.
Further you get very good syntax checking on it long before execution
starts. You can configure things other than simple strings.
 
R

Rhino

Chris Uppal said:
So far so good ;-)



It may, and in my experience nearly always does, make more sense to attach
the
constants to the class to which they pertain. I.e. while there can be
reasons
to create a class just to hold constants, it is rarely necessary or
desirable.

Ahh, now we get to the heart of the issue....

In my case, I have several classes that are writing various formats of
resumes. (Yes, that same project we've been discussing for weeks now.) The
various resume writer classes share a variety of constants, like the fonts
to use in particular parts of the document, the color palette to use, the
name of the log file to use for reporting errors, etc. I want all of the
classes in _this_ project to use certain values for those things but I don't
want all of the classes in _all_ of my projects to use those same values.

It makes no sense to me to define LOG_FILE_NAME separately in each of 10 or
15 classes that use it, particularly if there is a chance that I may want to
change the value of that constant. If my log file is current "Resume.log"
and I decide to change it to "CV.log", I _really_ don't want to have to
change its value in 10 or 15 separate classes; I just want to change it once
and have each class see the change.

Surely you're not suggesting that I should have 10 or 15 separate
definitions of LOG_FILE_NAME and then have to change each individually? This
seems like a very obvious case for storing these definitions once - whether
in an interface or a class - and then sharing them amongst all of the
classes that need them. Or does OO propose a different way althogether of
handling this very common situation?
(And, frankly, in those rare cases it makes no difference at all whether
you
use an abstract class or an interface -- it's a hack either way -- just
don't
make the mistake of trying to inherit ("extends" or "implements") the
class
containing the constants. Use the constants, don't inherit them).
Okay, fair enough. But what is the _right_ way to share constants amongst a
subset of your classes if interfaces or classes containing only constants
are a hack?
Classes that are clients of other classes can use the constants defined by
the
other classes if those constants are public (which they should be /if/
they
are intended for use by other classes).
How? Is this where 'import static' comes in, as Stephan and others have
suggested elsewhere in this thread?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,996
Messages
2,570,238
Members
46,826
Latest member
robinsontor

Latest Threads

Top