Re: Design Questions about static factory classes
On Sat, 22 May 2010, Arne Vajh?j wrote:
On 22-05-2010 15:05, Rhino wrote:
I'm thinking of a situation like completing a form in a GUI. The
customer has to enter his date of birth. Let's say that I can't use a
JSpinner for some reason; it can't do everything I need it to do. The
customer is given a simple JTextField for entering a date. Clearly, the
customer would have many opportunities to enter bad data. He could type
in 1985- 15-31 when he meant to type 1985-05-01; the first value is
obviously a bad date since there are only 12 months in the year, not
15. My practice is to write edits that check for that kind of mistake
and generate an exception, typically IllegalArgumentException, with a
clear error message that reminds the user that there is no such month
as '15'. Naturally, the customer might not be an English speaker so I
put all such messages in ResourceBundles so that other bundles can
easily be added for any languages that I support.
How would you handle such a situation?
Catch the exception but display something else that the exception text.
Exceptions texts are for log files to be handed over to developers.
For user input I don't even think that you should throw an exception.
Maybe just test and tell the user to correct.
Bad user input is not really exceptional enough to justify an exception.
I disagree. We've had arguments about the proper use of exceptions on this
newsgroup before, so i recognise that this is a matter where opinions
vary, but exceptions seem like a perfectly acceptable option for dealing
with bad user input to me. They might not be the right solution in every
situation, but they are an option that can be considered.
Of course, i wouldn't show the exception's error message to the user. An
approach i've seen is to do something like:
public class ValidationException extends Exception {
private final String validationKey;
private final Object[] parameters;
public ValidationException(String validationKey, Object.. parameters) {
super(format(validationKey, Locale.getDefault()));
this.validationKey = validationKey;
this.parameters = parameters;
}
public String format(Locale locale) {
return format(validationKey, locale);
}
private static String format(String validationKey, Locale locale) {
ResourceBundle bundle = ResourceBundle.getBundle("ValidationMessages", locale);
String pattern = bundle.getString(validationKey);
MessageFormat fmt = new MessageFormat(pattern, locale);
return fmt.format(parameters);
}
}
ValidationExceptions have a message in the language of the default locale
(or you could hardcode this to english if you wanted), which can be used
in logging and so on, but can also supply their message in other
languages, as needed.
If you put on a getter for the fields, then code that handles them can
also act on the key and parameters in other ways, as appropriate, if
simply printing the messasge is not adequate. Although in this case, you
should probably be using subclasses rather than switching on the contents
of the key. If you do subclass, you can refine the above approach by
pushing the parameters down into subclasses, accessed via an abstract
getParameters method in the base class. That lets you construct the array
on the fly from meaningful fields:
public class AgeTooYoungException extends ValidationException {
private final int actualAge;
private final int requiredAge;
// constructor
protected Object[] getParameters() {
return new Object[] {actualAge, requiredAge};
}
// getters
}
Code which catches this and is interested in the ages can then discover
them via proper getter calls, rather than having to scrub about in an
untyped parameter array.
Another refinement is to add a field which somehow indicates which bit of
user input was wrong - a simple string key might be enough. The UI code
can then attach the error message to the right bit of the UI simply by
matching that up.
tom
--
One horse laugh is worth a thousand syllogisms. -- H. L. Mencken