Do we really need singletons ?
At 10:06 PM on Mar 4, 2007, Pierre-Yves Saumont wrote:
There are tons of articles on the Web about how to implement a singleton : with or without lazy initialization, (broken ?) double check, class loader safe, serialization safe, etc. One of the more sophisticated I found is the Absolute Singleton from Inigo Surguy (http://surguy.net/articles/communication-across-classloaders.xml).
One of the simplest and smartest is the Initialization On Demand Holder idiom, that can be found at http://crazybob.org/2007/01/lazy-loading-singletons.html
However, I did not find any that solves the following problem :
Singleton instance1 = Singleton.getInstance(); Class cl = Class.forName("Singleton"); java.lang.reflect.Constructor[] c = cl.getDeclaredConstructors(); c[0].setAccessible(true); Singleton instance2 = (Singleton) c[0].newInstance();
This clearly produces two distinct instances, whatever singleton implementation you use.
One might argue that here we are breaking the singleton on purpose. True, but remember the definition of the singleton is "a class that offer the guarantee that only one instance of itself can be created", and not "a programmer that offer the guarantee that only one instance of the singleton can be created".
Same thing for the use of a security manager. In that case, the guarantee is given by the environment, and not by the class.
So, how can we create a true singleton ? The answer is: we can't. But the real question is "do we need a real singleton? Why would we?
First, note that a stateless singleton is nonsense. If the singleton is stateless, why should we care about the number of instances? We might want that as few instances as possible are created (for example if instantiation is costly), but in that case, we would probably not care about one or two more instances created in some marginal cases.
So, if the singleton is stateful, what we need is the singleton's state to be unique, not the instance. Here is a solution:
public class Singleton { static int count; int number; static class SingletonHolder { private static final Singleton instance = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.instance; } private Singleton() { number = ++count; } public int getNumber() { return SingletonHolder.instance.number; } }
Here, we use a counter to make the singleton stateful and allow us to verify that the singleton state is unique. The tricks are :
- unicity is due to the final state of the inner class field that holds the instance. Access to final fields may not be modified through reflection unlike constructors.
- fields accesses in method are redirected to the instance in the static inner class, so we only get the state of the original instance, even if other instances are created.
However, although this *seems* to solve the problem, it does not tell us why we should not prefer to use static fields to hold the state. After all, all singleton implementations use a static field to hold the singleton instance. The only reason I found is is given by Joshua Fox (http://java.sun.com/developer/technicalArticles/Programming/singletons/) :
"One of the strengths of the Singleton design pattern, as opposed to static methods, is that if you change your mind and want more than one, the Singleton class can be easily altered."
This is a bit like trying to sell an armored door made of plywood. It's much safer when you lose your keys.
Pierre-Yves Saumont
No comments:
Post a Comment