views:

479

answers:

5

We have constants declared in an interface in our application like this.

public interface IConstants
{
    public static final String FEVER="6";
    public static final String HEADACHE="8";
}

We now want to populate these constants values (6 and 8) from the database (or application servlet context).

The database values stored in a look up table are already available in the application session (in servlet context attribute) and hence I don't have to make a database call every time.

How do we accomplish this?

A: 

As constants, you can't readily.

Create a class with those members, protect the setters (or set them from the constructor) and provide getter methods.

More detail:

Okay, to start with, you can't readily initialize constants from a database because they must be initialized at the time they're defined.

Instead, create a class something like this:

public class Constants {
    private static final String FEVER ;
    private static final String HEADACHE ;

    public Constants(String fever, String headache){
        if(FEVER == null){
            FEVER = fever;
            HEADACHE = headache;
         } else {
            // Do something; shouldn't be resetting these.
         }
    }

    public String getFever(){ return FEVER; }
    public String getHeadache(){ return HEADACHE; }
}

Now, when you construct the class, you set FEVER and HEADACHE. Since they're static, there's only one value; since you have only getters and they're private, no one can reset them; and since they're final, no one can sneak behind your back with inheritance.

Charlie Martin
I am sorry, I didn't get it. Could you please be more detail?
@Charlie Martin: You can't set a static final constant in a constructor. You'd have to use a static initializer instead.
Michael Myers
Thank you very much for detailed explanation. Unfortunatly I have to work woth interface only. We are not in a position to change the design of the application. It is already live.So far there was no need to assign contant values from database. We just hardcoded them in the interface. But now they want to get them from database.
@mm Duh, you're right. Too little coffee. I'll figure it out and test it.
Charlie Martin
+1  A: 

Since the constant values are persisted in a database, the best approach would be to create an enum type and make them available through it.

kgiannakakis
You mean no Interface? Actually we are not in a phase to change the design of the application as it is already live. The interface exists and we need find solution keeping interface intact.So far there was no need to assign contant values from database. We just hardcoded them in the interface. But now they want to get them from database. Any suggestions are helpful.
A: 

To make them vary based on a data source, you'd need some kind of data structure for them.

You could define a bean to hold the values (fields with getters/setters), or use a map for the values.

You should probably think of this as more like a configuration problem than a constants problem. Constants are really intended from a programming point of view.

Scott Stanchfield
A: 

Are you sure you need to?!

If you need to add new code when adding a new disease anyways, there is little point in making the "constants" to be data driven static (non-final) globals. (It will just complicate things.)

  • If you are worried about a mismatch between the database and the code, you can verify that database and the constants match when starting up the application. You have the diseases defined in a table and are using some kind of referential integrity right?

  • If you DO think You need a data driven approach, you probably should not need any fields for "known diseases" at all, as the code shouldn't really depend on those. In that case each disease should be a proper object with a identity and other properties.

  • If you need special handling for certain types you probably should go back to an enum again...

  • If you instead have many diseases (that might be added dynamically) and only a few types - several diseases are handled in the same way by the same code; add a type in the disease-table and in the code as an enum (or constant) for the type-of-disease and use that to run different logic.

  • If each disease actually have a lot of complexity, it might be a good idea to try to write one class for each disease. (You can then do a proper O/R thing with sub-classes and all...)

The interface enum cludge is not neccesary since java 5, as you can get both enums and do a static import if you need to.

(And when using enum, validating the database is simpler as you get an enumeration for free.)

Your fields should probably be located in a class called Disease or SickDude instead of a gigantic global constants class. (Like, for instance, the fields in Calendar). Possibly as an inner public enum in the class where they "belong."

KarlP
+2  A: 

Given that you don't want to change the existing code too much, the simplest way would be:

public interface IConstants {
    public static final String FEVER = getConstFromDatabase("FEVER");
    public static final String HEADACHE = getConstFromDatabase("HEADACHE");
}
Michael Myers