Undoing a mess
In a project, the [Singleton pattern] was used to instantiate classes that were loading data into memory when the program was started.
In fact, Singleton does not serves to start data at the beginning of the program, but rather to guarantee a single instance (within a context) of a certain object.
It does not matter if the object is instantiated at the beginning of the program ( eager ) or at the first call to the lazy method.
Two implementations
public class Singleton {
private static Singleton eagerInstance = new Singleton();
public static Singleton getEagerInstance() {
return eagerInstance;
}
private static Singleton lazyInstance;
public static Singleton getLazyInstance() {
if (lazyInstance == null) {
synchronized (Singleton.class) {
if (lazyInstance == null) {
lazyInstance = new Singleton();
}
}
}
return lazyInstance;
}
}
Instantiating the object at the beginning of the program (or loading the class) is simpler because we do not have to worry about synchronization. However, the resources used are allocated even if they are not used.
Lets you instantiate the object on demand saves resources in some cases, but may cause a delay in responding to the first client using the feature and requires extra care with the competition. Yes, the two if
s are required to ensure 100% that there is no chance of loading the object twice on a concurrent call.
To Singleton or not to Singleton?
Now, think of the eager example and the following comment:
Why not call a static method where you load all this data into memory?
Loading the data into memory using a static method is pretty much what I did in the example above. So at the end of the day, your implementation is still a Singleton.
On the other hand, if you access the instances directly by an attribute, for example Singleton.instance
, then it really is not the Singleton pattern.
And this has several disadvantages, which go beyond the disadvantages of the Singleton standard itself, such as the encapsulation break and the high coupling between implementations.
Considerations
Ultimately, every design pattern is expendable.
Whoever has read the GoF carefully may have realized that the most cited side effect in standards is the increase in complexity and number of classes.
The truth is that there are much more direct ways of solving problems. The big difference between not using patterns and using them (properly) can be observed in the long run.
Solving a problem more simply and directly can cause an even greater maintenance problem. For example, using a static attribute as I mentioned above can cause serious problems if the way the system works changes. Imagine if it's no longer a Singleton tomorrow, but it needs to be ThreadLocal
(Singleton per thread). Serious errors can also emerge after load, performance, and concurrency tests that require synchronization of the retrieved object.
Finally, let's consider the last statement:
I can not think of any examples where it is not possible to replace any Singleton implementation with a simple use of static members.
In general, this is because there is no difference. The Singleton pattern is just a formalization of how to properly access a static attribute.