Is it recommended to have a static variable that maintains state?
I have an encryption utility method that relies on an external dependency --- a cipher key which is being retrieved from a property file. The way it can be retrieved in the current code base which I inherited is that it relies on creating new objects to be able to get the value of a property in the properties file. For example, if wanted to get the Cipher Key from the property file, it would be like this:
public synchronized static String encrypt(String someTextToEncrypt) {
String propertyValue = null;
propertyValue = getProcessCommonBase().
getProcessProperties.getProperty("CIPHER_KEY");
/*encrypt algorithm*/
return encryptedForm;
}
private synchronized static ProcessCommonBase getProcessCommonBase() {
if (processCommonBase == null) {
processCommonBase = new ProcessCommonBase();
}
return processCommonBase;
}
private static ProcessCommonBase processCommonBase;
EDITED: Design-wise is having a something like the processCommonBase instance variable a good practice to do? My understanding is that a good practice is that static variables should be final and do not change. In this case, however, the ProcessCommonBase class maintains state and is subject to change.
NEW QUESTION: If the static method relies on something external shouldn't I just mark the method and the processCommon base variable as non static and i开发者_如何学Cn Spring, just make a bean definition for it? What is better?
I agree with Joonas. I don't see why not make the variable final. Could you elaborate please what exactly do you mean by this:
My understanding is that a good practice is that static variables should be final and do not change. In this case, however, the ProcessCommonBase class maintains state and is subject to change.
Even if the variable is final, you still can change the object it references to in exactly the same ways as you'd do it with a non-final variable. That's why it's perfectly fine for a static method to have a static variable maintaining its state, but nothing stops you from actually making it final in this case. Why not do this:
private static ProcessCommonBase processCommonBase = new ProcessCommonBase();
Maybe there's something stopping you from creating processCommonBase at static initialization time, but it isn't obvious from the information you have provided.
Someone already commented your specific case, but in general, what you described is an effectively final static variable, which is just created "lazily" (that is, only when needed). It's a fine approach, if creating a ProcessCommonBase
instance is an expensive and rare event, although you must be careful to access it only via the getter method then. On the other hand, if a ProcessCommonBase
will be created whenever the surrounding class is used, then making it actually final is a better approach: it's simpler (less error prone, as you don't need to remember to use the getter method exclusively), and will actually be a bit cheaper, as the final variable is initialized only when the surrounding class is first used, and you don't need the (synchronized!) null check every time when accessing it (of course, if you use > 1 threads andProcessCommonBase
isn't thread-safe, then you need to synchronize somewhere).
Answer to your second question: being static vs. not and relying on some external system properties are two separate things. I don't know what Spring does, but if your method essentially a function - "value in, result out" - then it's a static method by its nature, even if it reads its configuration from some system property. Making such methods instance methods is possible, but if it only complicates things and gives nothing, why bother?
The usage of static is often frowned upon from an OO design perspective because it gives tight coupling between objects. With statics methods it’s impossible to decouple an interface from its actual implementation. This lack of decoupling can for example become a problem when you want to unit test a single class, as it can’t be separated from the other static parts.
In today’s Java landscape you’re singleton crypt class can be much better designed with the help of Dependency Injection (DI). The ProcessCommonBase could also be implemented as an DI singleton if it didn’t had that very strong code smell, because if it’s a god-object then it should be refactored, for example by using DI for injecting properties into you crypt class.
Example code based on Google Guice:
@Singleton
public MyCrypt {
private final key;
@Inject
MyCrypt(@CipherKey String key) {
this.pBase = pBase;
}
public synchronized String encrypt(String someTextToEncrypt) {
/*encrypt algorithm*/
return encryptedForm;
}
}
Configuring DI properties:
public class PropertiesModule extends AbstractModule {
@Override
protected void configure() {
String key = .. what ever ..
bind(String.class).annotatedWith(CiperKey.class).toInstance(key);
}
More DI examples can be found here: http://java.dzone.com/articles/cdi-overview-part-1
Populair Java DI implementations are: Guice, Spring and Java EE6.
精彩评论