Consider the following hypothetical Singleton class DateSingleton
which currently looks like the following:
public class DateSingleton {
private static DateSingleton instance = new DateSingleton();
private String year;
private String month;
private String day;
private DateSingleton() {
}
public static DateSingleton getInstance(){
return instance;
}
}
This Singleton can be thought of as a date keeper, and only one of them will exist for my entire web application. I would like to be able to make the following type of builder-style call to assign my state:
DateSingleton.getInstance().year("2015").month("February").day("25");
Can someone suggest what code I would need to add to the DateSingleton
class in order to make this possible? Is it considered bad practice to make a Singleton a builder?
I realize that I could just add getters and setters to accomplish the same funtionality. But I want to move away from this, as there may be many properties in this Singleton and the builder pattern makes the code much easier to use and read.
I would separate "I only need one value for my whole web service" from "this class should be a singleton". The latter is one possible implementation, but it's certainly not the only one.
I assume this is part of some configuration data somewhere. You can separate the "getting at configuration" from the configuration class, to start with. For example, you could have:
// TODO: Validation and thread-safety; see below
public final class ConfigurationHolder {
private static Configuration configuration;
public static void setConfiguration(Configuration configuration) {
ConfigurationHolder.configuration = configuration;
}
public static ConfigurationHolder getConfiguration() {
return configuration;
}
}
You'd then want appropriate synchronization, validation that by the time getConfiguration
is called, the configuration has been set, and probably validation that it's only set once, with maybe a resetForTest
method which does what it says on the tin.
At this point, Configuration
can be an immutable type with an appropriate builder - in your web app startup code, you'd build it with the builder, then set it, and then access it elsewhere.
Better in my view would be to use dependency injection to avoid having this global "holder" state in the first place. With dependency injection, in place, your startup code would still create the appropriate configuration using a builder, and then tell the DI framework that that's the configuration to use everywhere. Anything that needed a Configuration
would then get presented it at the appropriate time.
My experience is that that leads to clearer, more testable code.
See more on this question at Stackoverflow