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