06.09.08
Constants maintainence : Proposed solution
Almost all of us have used some sort of a common Constants class which gets piled with huge number of constants, ranging from things like SOME_IMPORTANT_ID to something trivial like INTEGER_VALUE_1. Whatever may be the reason, but the grouping of these things goes right against separation of concerns (as everything is virtually dumped in a single constants class). Some time back a common practice was to use Interface for declaring all constants and then allow for all classes to implement this interface to get all constants automatically. This solution needless to say was fast, but also outrageously wrong. Josh Bloch sums it pretty aptly:
- First of all, it causes a leakage of implementation detail into many unrelated classes in your code base, because any of the defined constant will be available to all of your classes when they implement this interface.
- As it is contained in the exported API of implementing class, clients of that class may get easily confused because it if of no consequence to the users of the class that it implements such an interface.
- Finally, it puts you into a commitment to ensure binary compatibility in the future, even though the class won’t need to use any of those constants.
Needless to say, I completely agree with all the above points, so what was the solution? well the solution was to come up with a common constants class in which you dump all your constants and add comments to group each in a certain way. Needless to say there will be some groupings which are outrageously funny. Like in one of the projects we had to check and constantize all integers, doubles, numbers. (refer to : Magic Numbers), due to lack of time (now thats new ain’t it?
), people were adding things like public static final int INTEGER_1 = 1 !!.
And top that with all things mixed up, one can be assured that the class turns out to be a mess. To top all of this java introduced a feature called static imports. Probably because many lame programmers were complaining that it is “too” much of an effort to precede the CONSTANT_NAME with its class, so it my class that has all the constants is called something like CONSTANTS, i would have to do something like CONSTANTS.CONSTANT_EMPLOYEE_ID or something in those lines to refer to any constant; So basically to solve this, java provides for static imports, all you have to do is import static XXX.XXX.XXX.CONSTANTS.* and viola! you don’t have to do that DOT thing anymore. This is Evil! How am I supposed to know that this constant belongs to this class only and not anywhere else?! needless to say my code gets more obfuscated and hard to read and maintain with static imports.
So where is the solution? Solution my friends lies in creating a common interface, generically tying it up to something and then creating separate place holders for each TYPE of constants. So if you want to group all IDs for example, use IDPlaceHolder which would implement this interface. Lets get started on how to do this. First we will create an interface called IConstantPlaceHolder like this :
// Java docs removed for clarity.
public interface IConstantPlaceHolder<T extends Serializable> extends Serializable {
// gets the value for the constant
public abstract T getValue();
// sets the value for the constant.
public abstract void setValue(final T value);
}
As you can see IConstant place holder is generically tied to a type "T" (let me know if you think of a better name than just a T
). It has two methods setValue and get value. It is a Common interface for constants that serves as a place holder for all constants grouped in a meaningful way. For example, all ID constants could be placed in one spot. A typical implementation would be something like:
public enum IDPlaceHolder implements IConstantPlaceHolder<Long> {
DEFAULT_ID(1008L);
private Long id;
// default constructor sets the value.
private IDPlaceHolder(final Long id){
setValue(id);
}
// get the value
public final Long getValue(final Long id){
return this.id;
}
// set the value
public final setValue(final Long id){
this.id = id;
}
}
Now all i have to do in client code is IDPlaceHolder.DEFAULT_ID.getValue() and i will have 1008L at my behest. It is expected and recommended that an IConstantPlaceHolder be implemented with the help of an enum, by using an enum one can take advantage of inherent type-safe features in java language. Similar to above we can/may have something like a place holder for all properties or association paths in Hibernate. For our purposes, lets take a simple example of simple string properties like first name, last name etc for an employee.
:
public enum GenericStringPropertyPlaceHolder implements IConstantPlaceHolder<String> {
// employee's first name.
EMPLOYEE_FIRST_NAME("Mahadev"),
// employee's last name.
EMPLOYEE_LAST_NAME("Shiva"),
// employee's address.
EMPLOYEE_ADDRESS("Brahmlok"),
// employee department
EMPLOYEE_DEPT("NA");
// the property value we want to set.
private String propertyValue;
// get the value
public final String getValue() {
return propertyValue;
}
//set the value
public void setValue(String value) {
this.propertyValue = value;
}
// constructor that sets the property value.
private GenericStringPropertyPlaceHolder(String propertyValue) {
setValue(propertyValue);
}
}
As you can make out, in my client code, I would do something like GenericStringPropertyPlaceHolder.EMPLOYEE_LAST_NAME.getValue() and i will get Shiva as the result. So basically to sum up what we have done in above to implementations is:
- Create an Enum which implements IConstantPlaceHolder<TYPE> which is generically tied to the TYPE of placeholder it is or can be.
- Set the attribute in the constructor and then basically declare the constants with the actual value being passed to them.
Advantages
Obviously, lot of you might be thinking at this point what is need for all this? well my justification is that when a project grows larger and larger, we will eventually end up with a file that looks bulky, bloated and all over the place and then at that point we would ask where is the separation of concerns that i love so much here ?. Trust me, even in a small project this can serve a lot of purposes by putting a constant to the place it belongs.
An improvement to the above place holder thing can be adding a MODEL in generic parameters and further restricting constants only specific to a model. I have not come with a final draft for the same, when i do, i’ll try to post it as a follow up. Btw, thanks for your encouraging emails and support, appreciate it and Stay tuned!
Regards
Vyas, Anirudh