Singleton vs. Just Create One
The case against Singleton
The Singleton pattern is elegant and natural. It's easy to see why it's become so popular. In this article I'd like to convince you to avoid making a habit of using it.The cannonical form of the Singleton pattern is:
public class Singleton
{
private Singleton() {}
private static Singleton instance = null;
public static Siggleton intance()
{
if (instance == null)
instance = new Singleton();
return instance;
}
}
This is so easy to understand, and so compelling in it's simplicity and convenience, that it has become one of the most popular of all the GOF design patterns. It seems to provide a way to mandate that no more than one instance of the Singleton object ever be created. Indeed, I have seen projects whose architectures are based on dozens of Singleton classes that form the entry points into the system.
But is Singleton the best way to achieve this? The Single Responsibility Principle (SRP) states that a class should have one and only one responsibility. A Singleton, by it's very nature, has at least two responsibilities. The first it it's primary function. The second it to ensure that only one instance be created. A strict interpretation of the SRP would suggest that one of those responsibilities should be moved out of the class.
Principles, however, are not laws. The benefits of Singleton may outweigh the subtle influence of an abstract principle. So we need more than just the SRP to make a case for avoiding Singleton. Pursuant to that end, consider this common variation of the Singleton (Which I will call SIS for Statically Initialized Singleton):
public class Singleton
{
private Singleton() {}
private static Singleton instance = new Singleton();
public static Singleton instance() {return instance;}
}
Clearly SIS is superior to the cannonical case in just about every way. It is faster, smaller, and simpler. The only benefit that cannonical Singleton has over thSIS is lazy evaluation. That is, the cannonical case does not make you pay for the creation of the Singleton unless you actually use it. (Of course this benefit is dubious at best. Why would you include a class that you did not intend to use?)
I can improve upon the SIS pattern, however. What you see below is something I call SINS for Statically Initialized Non-Singleton.:
public class Singulizer
{
public static NonSingleton nonSingleton = new NonSingleton();
}
public class NonSingleton
{
public NonSingleton() {}
}
Here I have conformed to the SRP by separating the enforcement of the singularity rule, from the class itself. It is the role of the Singulizer class to enforce singularity. You may protest that since the constructor of NonSingleton[?] is now public, there is no enforcement of singularity. True enough, the "enforcement" is by convention only. There would be a solution for this in C++. We could make the constructor of NonSingleton[?] private, and allow Singulizer to be a friend. Java, alas, does not give us this option.
We can enforce the convention by doing something draconian like this:
public class Singulizer
{
private Singulizer() {}
public static NonSingleton nonSingleton = new NonSingleton(new Singulizer());
}
public class NonSingleton
{
public NonSingleton(Singulizer s) {assert(s != null);}
}
But... eeeewwwwww!!
Besides, what are we afraid of? Can't we just tell our development team not invoke the constructor of NonSingleton[?]? Don't we trust our own teammates?
I understand that there are some cases (e.g. the creation of widely distributed libraries) where trusting teammates is not a viable solution to preventing unwanted multiple instantiations. On the other hand, most of us don't have that constraint. Most of us can simply attend a stand-up meeting, or a daily scrum, or some other group gathering and say: "Hay, don't anybody create instances of NonSingleton[?].
However, if we are going to trust our teammates to obey conventions (isn't that the definition of a team?) then why bother encapsulating the convention into a class. Why not simply create the single instances in main() and pass them into the rest of the system:
public static void main(String[] args)
{
MySystem s = new MySystem(new NonSingleton());
s.doWhatever();
}
I call this the Just Create One pattern, or JCO for short.
Now, if I haven't convinced you yet that Singleton should be avoided in most cases, consider the fact that Singleton makes it very hard to write unit tests. When we write unit tests, we want them to be independent from each other. We don't want Test2 to depend on the results of Test1. Indeed, we want to be able to run any test at any time in any order we wish. (Testing independence is a long held principle that I don't feel the need to defend here. But perhaps I'll defend it in another blog.) Singleton makes it very difficult to follow that rule without hauling down the entire execution context (e.g. JVM) for each test. What I want to do is create a new instance of the Singleton for each test case that I execute. However, this is precisely what Singleton prevents me from doing.
In my stilted view of the universe anything that impedes testing is something to be avoided. There are those who don't agree with this view, but I'll pit my defect rates against theirs any time. Testing considerations are very high on my list of important things, and I will gladly adjust my software designs to increase testability.
OK, having said all this, do I really avoid using Singleton? Yes, but I don't make a religion out of it. As I said above, there are cases where Singleton might make a certain kind of sense - especially if you don't trust the developers who will be using your classes. But in most instances, I think the very concept of singleness is flawed.
Append comments below:
- Dec 27, 2004, Brett Neumeier: There are some additional obscure problems that can come up when using Singleton in Java. Java doesn't guarantee that there is one instance of a static variable per virtual machine, it only guarantees that there is one instance of a static per defining ClassLoader[?] namespace. So if you're in a J2EE environment where (by specification) multiple ClassLoaders[?] are created by the container, you may be unpleasantly surprised when multiple Singletons get created.
- Nov 12, 2004, Mike Stockdale: But the singleton, besides guaranteeing singleness, also provides the ability to access that single instance. If we create the single instance at the 'top' of the system, how do we make it accessible to classes that need it down in the depths? Pass it as a parameter throughout the system? I don't think so. Create a (singleton!) registry that everyone can ask for it? But if this registry manages all single instances, then a class that just uses one will now depend on a class that depends on all of them. So a separate registry for each single instance? Now we're back to the singleton pattern. Am I missing something here?
- Passing the object as an argument is often the right thing to do. At least that option should be given the right of first refusal. In those cases where passing the argument is not the best idea, it can be loaded into a static variable in a context class somewhere rather than making the class itself it's own context. - UncleBob
- If the thread of execution of your application is guaranteed to run in one single thread, use ThreadLocals[?] to pass in objects without using method parameters. - GavinB[?]
- Nov 11, 2004, Rich MacDonald[?]: But Singleton works very well with unit testing, so long as you open up a little. 1) Make that attribute public or provide a set method. 2) Don't use it except for a) main app startup and b) test setup. For the latter, the setup() method of TestCase[?] simple sets that Singleton to whatever it wants. I generally have a TestSingleton[?] object which subclasses off Singleton and will insert that instead. Provides the test stubbing I need and works very well. Perhaps we should call this usage "Single Point of Access" rather than "Singleton", because you may be using different subclass instances rather than the Singleton instance.
public class Singleton
{
private Singleton() {}
private static Singleton instance = null;
public static Singleton instance()
{
if (instance == null)
setSingleton(new Singleton());
return instance;
}
public static void setSingleton(Singleton singleton){
instance = singleton;
}
}
public class TestCase{
public void setup(){
Singelton.setSingleton(new TestSingleton());
}
}
public class MainClass{
// No need to do anything. Just use lazy initialization
}
- (continued...)
- Why would this be better than simply setting a static variable in both setup() and main()? - UncleBob
- Another variation is to add a static reset method to the singleton that is called in setUp/tearDown. Then test cases are isolated from each other again. But in that case and in the code sketched above you loose the safety of the singleton: by misuse of the setSingleton/reset method you can have more than one instance of the singleton class. Having said that you can simply use a regular class und avoid creation of several instances by convention. - Stefan Roock
- Nov 12, 2004, Marc Rohloff: I think it is a mistake to tie lazy evaluation to the singleton pattern. It is just a common way of implementing it. I usually use Lazy evaluation with a different goal, delaying object creation until the object is needed. SPecifically I usually use it when I know the object may not be required in certain code paths or that the program may terminate before the code is needed. For example it is a waste to create all your singletons if your application is going to terminate when analysing the command line parameters.
- The GOF book makes it pretty clear that lazy evaluation (LE) is part and parcel of the Singleton pattern. Of course I've seen variations that don't use LE, but the norm is for singleton's to have that if statement in the instance() method. As for it being a "waste" to create singletons if the application is going to terminate early, I think you can simply create your single objects after the command line has been analyzed. Even if you created them early, what exactly would be wasted? Milliseconds aren't particularly important if you are simply goint to abort and return to the command line. - UncleBob
- In Java, even without LE the singleton won't be created before the class is loaded, which often will be when the Singleton is used for the first time. - IljaPreuss[?]
- Nov 17, 2004, Jim Standley: Other parts of GoF[?] on Singleton are not often mentioned ... a page or two on how to subclass singletons and use factories or registries to create them. Some pretty cool stuff. Is servlet a good example of Just Create One? The constructor is public, but what would you ever do with one if you made it?
- Yes, I think Servlets are a perfect example. - IljaPreuss[?]
- Nov 18, 2004, Johan Nilsson: I don't know if we're locked into Java here, but I rarely implement domain objects (directly) as singletons in C++. The main reason was that they were totally hopeless to unit test, as implied in the text. So do I not use singletons then ... of course I do. I'm especially fond of using an Eventlog singleton. What I do now is to develop the would-be singletons as normal classes, test-first. I can then easily make them singletons by applying a template to the class; as simple as a one-liner inside a specific header file, e.g. "typedef Singleton<MyClass[?]> GlobalMyClass[?]". These parameterized singletons are named as Global<whatever> and put into Global<whatever>.h by convention. As for lazy vs non-lazy (did I get off-topic here somehow) - I've always used the lazy implementation without even reflecting over that. Thanks for making me think about it.
- I was already thinking along these lines for some months now, and it is really nice to finally have a name for the concept. I already used the name Just Create One in several discussions, and I hope that giving it a pattern-like name will help the concept to be more easily accepted... :) - IljaPreuss[?]
- Nov 23, 2003: Ilja Preuss: I think that biggest problem with singleton is that it is similar like globals in vb. I always thought that people discovered singleton to make globals pretier, but as book says you cannot use globals because anyone can change it (every piece of code has access) - the same with singleton - everone can use it and change and you cannot find bug if there is one. Any comments?
- Singletons are globals. They are just cleverly disguised. Thus they should be used with the same caution that is applied to globals. BTW, globals are not intrinsically evil, they are just something to be careful with. -- Uncle Bob.
- Dec 2, 2004: Ronald Matt: How about Prototype? It has at least two responsibilities. Should one of those responsibilities be moved out of the class?
- Dec 14, 2004: Volker Zink: I often don't create an instance at all. That means i use the class itself like a singleton. Many don't like it, but its really practical if there is no initialization issue (i am programming in Smalltalk).
- A Class in Smalltalk is essentially a singleton instance of its MetaClass[?]. Since you can attach behaviour to Class objects in ST, you don't really need to create a Singleton. --- Steve Rees
- Jan 8, 2005: I also have this pattern (create only one). Of all the GOF patterns, I never really liked Singleton. Some of it was the recognition as others described above, that singletons are just disguised globals, with all the same problems that free-for-all access can encourage. The alternative, of passing objects as parameters to classes that need to use them, can seem like a lot of trouble initially - who wants to pass a whole bunch of object around that are just handed down for lower levels to use. However introducing classes to group related objects will reduce the burden. Moreover it opens a number of possibilities, starting with the ability to add behaviour to the new classes. A second point: I find it hard to think of entities that truly are intrinsically singular. For example the singleton pattern could be used to provide access to "the database" for a system, but what happens when the requirement comes in for accessing more than one database? -- Phil Dennis
- February 19, 2005:
- That is, the cannonical case does not make you pay for the creation of the Singleton unless you actually use it.
- Feb 26, 2005: Sometime ago I came across this article, http://www-106.ibm.com/developerworks/library/co-single.html, and proceeded to create my own singleton registry. It's a little cumbersome at the beginning but it works very well with unit testing. -- Rolly Ferolino
- Mar 04, 2005: I have often seen systems where singletons where placed in the base layer. Really a lot of classes used the singletons. That really maked testing a hell since you can only guess which singletons you have to initialize. These systems often had a catch all initializer class that resetted all singletons. Since nobody knew exactly which singletons to initialize for a given test, the catch all initializer was used as a m talisman in every test case. That was a real mud. -- Stefan Roock
- Apr 13, 2004: Have you tried double-checked locking? As of Java 1.5 it is reliable. See code below...
public final class Singleton() {
private static Singleton instance;
private Singleton() { }
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
This way should work just fine. Reference: Head First Design Patterns (ISBN 0596007124)
I'm programming in C#, and whenever I want a singleton I use IServiceProvider as it's described in here: http://weblogs.asp.net/cazzu/archive/2004/05/10/129140.aspx
Not only it simplifies testing, but also it allows to choose implementation at higher level.
Instead of singleton I just think about service. In all cases I want singleton, it worked very well.
Not only it simplifies testing, but also it allows to choose implementation at higher level.
Instead of singleton I just think about service. In all cases I want singleton, it worked very well.
My only concern is over the issue of trusting teammates. Developers come and go. Intentions are forgotten over time. In many cases software is developed by one team and handed over to another team to maintain.
Singletons have their use. I use Singleton to store static (lookup) data so that any class that needs it can have access to it. This class (called ConfigData[?]) is initialized at start-up time only, lookup and configuration data can be "reloaded" at will. Nothing else can change its state. Hence, many of the problems mentioned in this article and the comments simply do not occur.
The other time I may use a Singleton is something like an Application class. generally, I use it to initialize application specific data at start-up. Once again, we have at most one such class in the application, and it is initialized at start-up and state change can only occur by re-loading it. Hence, we manage to avoid all these problems.
Unit testing is not a problem at all. If a class depends on the data loaded by the Singleton class, just use the Singleton.getSingleton() static method. If it is already loaded, then it will simply get the pre-loaded data and not load it again.
The other time I may use a Singleton is something like an Application class. generally, I use it to initialize application specific data at start-up. Once again, we have at most one such class in the application, and it is initialized at start-up and state change can only occur by re-loading it. Hence, we manage to avoid all these problems.
Unit testing is not a problem at all. If a class depends on the data loaded by the Singleton class, just use the Singleton.getSingleton() static method. If it is already loaded, then it will simply get the pre-loaded data and not load it again.
Add Child Page to SingletonVsJustCreateOne