Yet Another “Singletons Are Evil” Rant
The issue with Singletons is twofold. First, it is not a problem that you’d like to enforce only one instance of something within a system. It is a problem that you are enforcing only one instance of something within a system using the Singleton pattern. Why?
1. You are coupling every client of the class with the knowledge the class has only one instance. This comes from C++’s distinct syntax for obtaining the instance of a Singleton. This (a) very much violates the intent of encapsulation in object-oriented systems, (b) is a violation of DRY, and (c) is a violation of the Uniform Access Principle (or a slight generalization of it in any case).
2. In order to unit test effectively, you need to exercise different states. With some common usages of singletons, not all interesting states are reachable. Even the states which are reachable are more difficult to reach.
To give an example, I maintain a Java application which uses Singleton pattern for its configuration data object. You might think this is reasonable, since an application can have only one configuration, and that is an essential property of the system’s configuration, correct? The object’s getInstance() method deserializes the configuration object from some XML on disk on the first invocation, and reuses the object on subsequent invocations.
Now, how do I unit test this system? Let’s say I have some configurable object that can exhibit two kinds of behavior. I can write the XML in our testing directory one way, and test one kind of behavior, or I can write it the other way and test the other kind of behavior. Alternately, I can add a reset() or setInstance() to the Singleton, making it no longer a Singleton, and write machinery which modifies the config then essentially reboots the system. This is a lot of extra work. If you pay careful attention to what you’ve just done, you’ve replaced Singleton with something that I am now dubbing “Service Injection by Global Variable.”
It gets worse: Even for classes in the system where I can inject parameters, the parameters themselves, or far removed dependencies of them or the object, may depend on other global mutable state. If I have a system where Singletons are common, this erodes my confidence that my unit tests guarantee correct execution of my program. This is just the same old “global variables” argument – it is more difficult to reason about programs because you need to know not just the interface of an object and its liftetime, but also the global mutable state on which it depends to predict its behavior.
Solutions:
1. There are dependency-injection frameworks (e.g. Spring, in Java-land) that allow you to declare singleton instances in a way such that the same instance is injected to every object that requests the instance. This is not a problem, even though the word “singleton” appears: (a) the client code is not coupled with the knowledge that such an object is singleton, and (b) the knowledge that an object is singleton is expressed in a single place, and (c) the client code is identical regardless of whether the object is a singleton.
2. When you aren’t using a dependency-injection framework, injection (either by constructor or setter) is still the “right” route. I know that it seems hard, but there are plenty of tricks to make it easier, especially in C++ – the simplest of which is aggregating the most commonly used of the system’s services into a parameter object. In addition to what I’ve said above, this is the “right” choice because the application’s application object (for example) rather than the class providing some service should be the single point of knowledge deciding whether some service should be singleton across the application.
