Placement of Constants - again

R

Rhino

I'm trying to implement the advice I was given the other day about the
placement of constants that were shared in various classes of my project.
I've managed to thin out my FooConstants class considerably on that basis of
that advice but I'm having specific cases that are giving me trouble.

First, let me begin by correcting an inadvertent misstatement I made about
this project. I said that it was generating resumes in various formats and
that all of the files were being kicked off by a single class
(ResumeFileGenerator, although I didn't state its name previously). As I
look at the code again a bit more closely, I see that this is not quite the
case. A standalone class called ResumeApplet displays my resume in the form
of an applet.

Now, several of the classes that generate resumes, including ResumeApplet,
are making use of colors from a specific palette of colors that are embodied
in an enum. The enum lists several color palettes and each palette has a
color to be used for displaying text, and some contrast colors for use in
JPanels or HTML or in heading text in PDFs. I want to make sure that all of
the classes that generate Resumes use the exact same color palette to do
their jobs; I don't want the applet to use a predominantly red palette while
the HTML page uses a predominantly green palette. Every instinct I have says
that I should be establishing exactly which palette I want to use ONCE for
the project and that all classes should use that same palette.

Clearly, the color palette is not a file/path kind of information that might
best be situated in a properties file and isn't a String anyway. Does this
constitute "configuration" information? If so, where do I put it? And if
it's not configuration information, where should I put it so that all
classes in the project use that specific color palette? It's just one line
of code:

ColorPalette colorPalette = ColorPalette.BLUES;

but I'm really struggling with where it needs to be. I need to be sure that
other classes in the project don't suddenly start using ColorPalette.REDS
(or whatever) and that's the obvious risk if I have a line defining which
colorPalette I want in each class that needs colors.

I was thinking of establishing the color palette in the ResumeFileGenerator
class, probably in the constructor, and then passing a reference to each
class that needed it but this won't help me with the standalone
ResumeApplet.

--
I have a few other constants which strike me as problematic too, although
the color palette feels like the big one. Let me mention these too now in
case they have different solutions than Color Palette.

Several of the classes write the word "Resume" in one or another places and
I am trying to write it so that the acute accents on the two e's appear
correctly. I've got several constants for the different variations:

public static final String RESUME_HTML_LOWERCASE = "résumé";

public static final String RESUME_HTML_CAMELCASE = "Résumé";


public static final String RESUME_UNICODE_LOWERCASE = "r\u00e9sum\u00e9";

public static final String RESUME_UNICODE_CAMELCASE = "R\u00e9sum\u00e9";

I need the first two in HTML documents that are being generated and the
latter two in ASCII, PDF, and CSS documents that are being generated. Since
each of these is used in at least two different classes, I'm not sure where
best to place these.

All of the classes in the project share a common set of ResourceBundles. (I
want to keep open the possibility of generating resumes in foreign languages
since I have a working knowledge of two other languages and could picture
working in countries where those languages are spoken. I haven't actually
translated phrases like "Job Target" or "Format Education" to the other
languages but I _could_ and might do that.) The base name of the
ResourceBundles is used in both ResumeFileGenerator and ResumeApplet. Where
should I put its definition so that both classes use the exact same name?

Lastly, let me raise the case of what I'll call a "convenience constant". I
tend to prefer writing the name of a String constant called NEWLINE rather
than a "\n" in my statements simply because
the former seems a little clearer to me. I've used this technique in many
classes in many projects so this constant has much wider scope than just
this one project. Would it make sense to have a class of constants in my
Common project and just accumulate any similar widely used constants there?
If not, what is a better way to handle this kind of situation? Let me stress
that these "convenience constants" are not a big deal to me; if good OO
design opposes the very notion and prefers use of "\n" in all cases rather
than a constant, that's fine by me. I'm just trying to understand how a
constant that is widely used in many projects should be handled.

One (or more) of the responders to my original question said that classes
containing Constants weren't absolutely unthinkable, although there were
usually better ways. I haven't stumbled on exceptions that really DO belong
in a FooConstants class have I?
 
T

Tom Anderson

It's just one line of code:

ColorPalette colorPalette = ColorPalette.BLUES;

but I'm really struggling with where it needs to be.

Presumably, you have a Resume class (or even better, a
ResumePresentation). Who makes instances of that? Where does it get its
information from? Where, for instance, is your name stored?
Several of the classes write the word "Resume" in one or another places
and I am trying to write it so that the acute accents on the two e's
appear correctly. I've got several constants for the different
variations:

public static final String RESUME_HTML_LOWERCASE = "résumé";
public static final String RESUME_HTML_CAMELCASE = "Résumé";
public static final String RESUME_UNICODE_LOWERCASE = "r\u00e9sum\u00e9";
public static final String RESUME_UNICODE_CAMELCASE = "R\u00e9sum\u00e9";

I need the first two in HTML documents that are being generated

Not necessarily - if you're using a character encoding that contains the e
with an acute accent, like UTF-8 or ISO-Latin-1, you can just use it
directly, rather than writing an escape.
and the latter two in ASCII,

You aren't going to have a lot of luck using those in ASCII documents,
considering that those strings have non-ASCII characters in. Did you mean
'plain text (in some suitable character encoding)'?
PDF, and CSS documents that are being generated.

Since each of these is used in at least two different classes, I'm not
sure where best to place these.

Firstly, i'd be tempted not to do this with constants, but to write the
string once (in a resource bundle), and use methods to (a) escape
characters for HTML and (b) twiddle the case of the leading letter. Then,
if you change the string in question, you only have to change one string
literal, rather than four.

Secondly, if there is a constant which is used by several classes, and
more than one of them has a strong claim to ownership of the constant,
then it can certainly go in some constant-holding class or interface. Such
things are to be avoided where possible, but are the right solution when
that is not possible.
All of the classes in the project share a common set of ResourceBundles.
(I want to keep open the possibility of generating resumes in foreign
languages since I have a working knowledge of two other languages and
could picture working in countries where those languages are spoken. I
haven't actually translated phrases like "Job Target" or "Format
Education" to the other languages but I _could_ and might do that.) The
base name of the ResourceBundles is used in both ResumeFileGenerator and
ResumeApplet. Where should I put its definition so that both classes use
the exact same name?

Same problem as above. This belongs to whoever is in charge of making
Resume objects. If there are several places where Resume objects are made,
then refactor until there is only one, and put it there.
Lastly, let me raise the case of what I'll call a "convenience
constant". I tend to prefer writing the name of a String constant called
NEWLINE rather than a "\n" in my statements simply because the former
seems a little clearer to me. I've used this technique in many classes
in many projects so this constant has much wider scope than just this
one project. Would it make sense to have a class of constants in my
Common project and just accumulate any similar widely used constants
there? If not, what is a better way to handle this kind of situation?
Let me stress that these "convenience constants" are not a big deal to
me; if good OO design opposes the very notion and prefers use of "\n" in
all cases rather than a constant, that's fine by me. I'm just trying to
understand how a constant that is widely used in many projects should be
handled.

Firstly, you should probably be saying
System.getProperty("line.separator") rather than "\n", so you get the
right line ending on heathen platforms.

Secondly, i know of no OO or general programming principle that opposes
constants like that in the general case. The same analysis as above
applies: if they're owned equally by several classes, but them in some
neutral place, like a constants class.
One (or more) of the responders to my original question said that
classes containing Constants weren't absolutely unthinkable, although
there were usually better ways. I haven't stumbled on exceptions that
really DO belong in a FooConstants class have I?

Sounds like it.

tom
 
R

Rhino

Tom Anderson said:
Presumably, you have a Resume class (or even better, a
ResumePresentation). Who makes instances of that? Where does it get its
information from? Where, for instance, is your name stored?
The DATA on the resume is all stored in a ResourceBundle, including my name,
email address, job target, experience and all of that. The labels used to
present that information, like "Job Target", "Formal Education" etc. are
likewise stored in the same ResourceBundle.

I have a Resume class. It's job is to find the obtain the information from
the ResourceBundle. It is basically a bunch of small getters, like
getJobTargetText() which returns the label "Job Target" (it would return the
French translation of Job Target if I create a French-language resume) and
getJobTargetData() which returns the jobs that I am targeting with this
resume.

ResumeFileGenerator kicks off most of the classes which create resumes. I'm
not sure the proper name of this kind of class - driver? framework? - but it
instantiates all but one of the classes that generate a resume.
ResumeFileGenerator is a plain Java application, not a servlet or whatever.
The code in ResumeFileGenerator looks like this:

public class ResumeFileGenerator {

public static void main(String[] args) {


ResumeFileGenerator resumeFileGenerator = new ResumeFileGenerator();

resumeFileGenerator.generateResumes();


System.out.println("\n===Program ends===");

}


public ResumeFileGenerator() {


localizationUtils = LocalizationUtils.getInstance();

resumeResources = localizationUtils.getResources(Locale.getDefault(),
ResumeConstants.LIST_BASE);


/* Establish the color palette that will be used by these classes. */

ColorPalette colorPalette = ColorPalette.RC_BLUES;


/* Get database connection. */


/* Set up logging. */

}



/**

* Generates various resume files.

*/

public void generateResumes() {


/* Get an instance of the data that will be used by all of the resume
writers. */

Resume resume = new Resume(resumeResources);


/* Write the resume in HTML format. */

ResumeFileWriterHtml resumeFileWriterHtml = new ResumeFileWriterHtml();

resumeFileWriterHtml.writeResume(resume);


/* Write the resume in ASCII format. */

ResumeFileWriterAscii resumeFileWriterAscii = new ResumeFileWriterAscii();

resumeFileWriterAscii.writeResume(OUTPUT_FILE_PATH +
ResumeFileGeneratorConstants.RESUME_ASCII_FILE, resume);


/* Write the resume in property format. */

ResumeFileWriterProperty resumeFileWriterProperty = new
ResumeFileWriterProperty();

resumeFileWriterProperty.writeResume(OUTPUT_FILE_PATH +
RESUME_PROPERTY_FILE, resume);


/* Write the resume in PDF format. */

ResumeFileWriterPdf resumeFileWriterPdf = new ResumeFileWriterPdf();

resumeFileWriterPdf.writeResume(OUTPUT_FILE_PATH +
ResumeFileGeneratorConstants.RESUME_PDF_FILE, resume);

.....

}

}


That's the gist of it.

ResumeApplet is a standalone applet that also uses the colors from the color
palette for painting the resume.

I don't have a ResumePresentation class at all. Is a "Presentation" class
part of one of the design patterns? I'm afraid I don't know those very
well.... If I should be using a particular design pattern here, which one
should I use? I have some Design Pattern links and can find examples of the
desired patterns use if you can point me to the one I should be using.....
Not necessarily - if you're using a character encoding that contains the e
with an acute accent, like UTF-8 or ISO-Latin-1, you can just use it
directly, rather than writing an escape.


You aren't going to have a lot of luck using those in ASCII documents,
considering that those strings have non-ASCII characters in. Did you mean
'plain text (in some suitable character encoding)'?
Honestly, I don't remember why I created the escaped versions any more. They
seemed necessary at the time and they work in the sense that the accents
appear where they should but I may be able to revise them to simply use a
direct e-acute rather than the escaped versions. I'll look into that and
change it if I can. However, I still need each version of each string in at
least two different places so I still need to understand where to place the
definitions.
Firstly, i'd be tempted not to do this with constants, but to write the
string once (in a resource bundle), and use methods to (a) escape
characters for HTML and (b) twiddle the case of the leading letter. Then,
if you change the string in question, you only have to change one string
literal, rather than four.
Fair enough.
Secondly, if there is a constant which is used by several classes, and
more than one of them has a strong claim to ownership of the constant,
then it can certainly go in some constant-holding class or interface. Such
things are to be avoided where possible, but are the right solution when
that is not possible.
There are indeed multiple classes that use each string and no obvious
candidate for which one is more of an owner than any of the others.

I'm not really trying to get permission to use a Constants class here; I
just want to make sure I've exhausted all other reasonable alternatives
before using a Constants class. I'm just not sure if I have exhausted all
the other reasonable possibilities or whether I'm overlooking better
approaches.
Same problem as above. This belongs to whoever is in charge of making
Resume objects. If there are several places where Resume objects are made,
then refactor until there is only one, and put it there.
Hmm. I'm not sure I'm understanding you correctly. Based on my description
so far (in the original post and this followup) would you agree that
ResumeFileGenerator is the place where the Resume objects are made? Or are
you talking about the specific classes that generate each Resume, like
ResumeFileWriterAscii, ResumeFileWriterHtml, ResumeFileWriterPdf and so
forth? And what about my standalone ResumeApplet? The resume in that is NOT
created by ResumeFileGenerator.
Firstly, you should probably be saying
System.getProperty("line.separator") rather than "\n", so you get the
right line ending on heathen platforms.
Good point ;-)

And that basically eliminates the issue in this case....
Secondly, i know of no OO or general programming principle that opposes
constants like that in the general case. The same analysis as above
applies: if they're owned equally by several classes, but them in some
neutral place, like a constants class.
Okay, that sounded logical to me but I'm trying to be sure I haven't
overlooked other important considerations.

Even if my NEWLINE constant is not an issue any more, I can picture other
constants that may arise that ARE used in many classes. It's good to know
that some constants in a Common project that are (potentially) shared by all
projects are not going to present a problem.

Sounds like it.
I'm surprised. I had assumed that I was just missing some obvious (to you)
alternate techniques....
 
M

Martin Gregorie

The DATA on the resume is all stored in a ResourceBundle, including my
name, email address, job target, experience and all of that. The labels
used to present that information, like "Job Target", "Formal Education"
etc. are likewise stored in the same ResourceBundle.
Since you seem likely to want to generate language-specific resumes I
think there's a case for breaking up the resource bundle into one locale-
independent one, which holds all items that are constant no matter what
language is being used, e.g. your name, address, date of birth, etc, and
a set of locale-dependent bundles which would contain information which
is locale-dependent such as language-specific headings and boiler-plate
as well as locale-dependent formatting for dates, time, money, etc.

With this approach you don't end up copying invariant data into multiple
resource bundles and running the risk of forgetting to update them all.
 
J

Jean-Baptiste Nizet

Since you seem likely to want to generate language-specific resumes I
think there's a case for breaking up the resource bundle into one locale-
independent one, which holds all items that are constant no matter what
language is being used, e.g. your name, address, date of birth, etc, and
a set of locale-dependent bundles which would contain information which
is locale-dependent such as language-specific headings and boiler-plate
as well as locale-dependent formatting for dates, time, money, etc.

With this approach you don't end up copying invariant data into multiple
resource bundles and running the risk of forgetting to update them all.

This isn't necessary. You just have to place all the locale-
independent items in the base resource bundle (the one without any
locale at the end), and the locale-dependent items in each of the
locale-specific bundles.

Example :

myBundle.properties :
# invariant : no need to redefine in locale-specific bundles
lastName=Rhino
firstName=John

# default if not defined in locale specific bundle
dateOfBirth=1st May, 1975

myBundle_fr.properties :
# dateOfBirth redefined for French
dateOfBirth=1er mai 1975

When you'll ask for the value associated with the key "firstName",
using the locale "fr", the myBundle_fr resource bundle will fall back
to its parent myBundle resource bundle, because it doesn't have the
key.

No need for two separate set of bundles for this.

JB.
 
R

Rhino

Jeff Higgins said:

I think you may have misunderstood my remark. The code I posted was REAL
code that compiles and was lifted from the class. I didn't provide all of
the code since it was very repetitive and it seemed pointless to show the
repetition. That's what I meant when I said it was the gist: not that it was
pseudo-code but that it was an excerpt. Sorry if my poor phrasing gave you
the wrong impression....
 
R

Rhino

Martin Gregorie said:
Since you seem likely to want to generate language-specific resumes I
think there's a case for breaking up the resource bundle into one locale-
independent one, which holds all items that are constant no matter what
language is being used, e.g. your name, address, date of birth, etc, and
a set of locale-dependent bundles which would contain information which
is locale-dependent such as language-specific headings and boiler-plate
as well as locale-dependent formatting for dates, time, money, etc.

With this approach you don't end up copying invariant data into multiple
resource bundles and running the risk of forgetting to update them all.
Fair enough. There isn't much that's invariant though. While my name won't
change, pretty much everything else would need to be translated if I
produced a foreign language resume.
 
J

Jeff Higgins

Actually, I'm not adverse to adding yet another format and XML would seem to
be a good choice....
Yes, especially considering JAXP.

Code lifted from Real's How To:
<http://www.rgagnon.com/javadetails/java-0407.html>

// jdk1.4.1
import javax.xml.transform.*;
import java.net.*;
import java.io.*;

public class HowToXSLT {
public static void main(String[] args) {
try {

TransformerFactory tFactory = TransformerFactory.newInstance();

Transformer transformer =
tFactory.newTransformer
(new javax.xml.transform.stream.StreamSource
("howto.xsl"));

transformer.transform
(new javax.xml.transform.stream.StreamSource
("howto.xml"),
new javax.xml.transform.stream.StreamResult
( new FileOutputStream("howto.html")));
}
catch (Exception e) {
e.printStackTrace( );
}
}
}
 
J

Jeff Higgins

I think you may have misunderstood my remark. The code I posted was REAL
code that compiles and was lifted from the class. I didn't provide all of
the code since it was very repetitive and it seemed pointless to show the
repetition. That's what I meant when I said it was the gist: not that it was
pseudo-code but that it was an excerpt. Sorry if my poor phrasing gave you
the wrong impression....
Don't be sorry. It was your poor uncompilable code ...

public ResumeFileGenerator() {


localizationUtils = LocalizationUtils.getInstance();

resumeResources = localizationUtils.getResources(Locale.getDefault(),
ResumeConstants.LIST_BASE);

.....

}
 
T

Tom Anderson

This isn't necessary. You just have to place all the locale-
independent items in the base resource bundle (the one without any
locale at the end), and the locale-dependent items in each of the
locale-specific bundles.

Martin was making the point that this might not be a good idea - look at
his last paragraph again. If you do that, then there's a risk that when
preparing a localisation, you copy the whole file, including the
locale-independent items, and fail to delete them from it. You then have
the same information in two places. If you ever need to change the
information, you have to change it twice.

It's probably not a big risk, particularly in this situation. But it's one
that can be designed out altogether.

tom

--
Also, thinking about that Velociraptor thing, I think -- what with having
trained on turkeys, guineafowl, geese, large chickens, swans and peacocks
as a child -- that I could take a Velociraptor. I'd need a large hessian
sack, some baler twine, and a hook to hang it from. And gloves. Not to
forget the gloves. -- cleanskies
 
T

Tom Anderson

The DATA on the resume is all stored in a ResourceBundle, including my name,
email address, job target, experience and all of that. The labels used to
present that information, like "Job Target", "Formal Education" etc. are
likewise stored in the same ResourceBundle.

I have a Resume class. It's job is to find the obtain the information from
the ResourceBundle. It is basically a bunch of small getters, like
getJobTargetText() which returns the label "Job Target" (it would return the
French translation of Job Target if I create a French-language resume) and
getJobTargetData() which returns the jobs that I am targeting with this
resume.

Okay, then make the palette a property of the Resume class. Other code
which is interested in the palette says:

Resume r;
ColorPalette = r.getPalette();

You then just have to decide how to implement that getter. I'd start with
the simple way:

public ColorPalette getPalette() {
return ColorPalette.BLUES
}

If you later decide you want data-driven palettes, you could load the
choice from your resource file, or from some other configuration file.

The important point is that everyone who needs to know a palette can just
ask the Resume for it.
I don't have a ResumePresentation class at all. Is a "Presentation"
class part of one of the design patterns?

No, sorry, i was thinking out loud and hoping that the name would make my
meaning clear, which of course it doesn't even come close to doing.

My thinking was that there's a difference between a resume (information
about who you are and what you've done) and the way a resume is presented
(layout, fonts, colours, etc). My suggestion above of putting the palette
on the Resume object conflates these two ideas. Now, conflation isn't
acutely poisonous, but it's a chronic toxin that should be avoided. In
this case, i was thinking of factoring out a ResumePresentation class that
held presentation-specific information. The palette would then be a
property of that. You could have the ResumePresentation class refer to the
Resume it presents (but not vice versa - a resume should not know or care
about its presentation), or you could make ResumePresentation
Resume-agnostic, and only have them interact when the time came to do some
presentation.
Hmm. I'm not sure I'm understanding you correctly. Based on my
description so far (in the original post and this followup) would you
agree that ResumeFileGenerator is the place where the Resume objects are
made? Or are you talking about the specific classes that generate each
Resume, like ResumeFileWriterAscii, ResumeFileWriterHtml,
ResumeFileWriterPdf and so forth? And what about my standalone
ResumeApplet? The resume in that is NOT created by ResumeFileGenerator.

In which case the second sentence in the paragraph applies. Factor out a
factory for Resumes (which could be as simple as a static factory method
on Resume), and share it between the ResumeFileGenerator and the
ResumeApplet.

tom

--
Also, thinking about that Velociraptor thing, I think -- what with having
trained on turkeys, guineafowl, geese, large chickens, swans and peacocks
as a child -- that I could take a Velociraptor. I'd need a large hessian
sack, some baler twine, and a hook to hang it from. And gloves. Not to
forget the gloves. -- cleanskies
 

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

Similar Threads


Members online

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top