The most common, canonical use of the Singleton pattern irritates me. Every time I see it, I think, “The singleton-ness of a class is an implementation detail, and shouldn’t leak out through that class’s interface.” Yet, that’s what it always does.
In the usual implementation, someone decides that some new class they’ve written is so resource critical, or so standalone, or so useful that they can have only one instance of that class and that instance has to be visible everywhere. Ignoring the intricacies of threading and so on, a Singleton usually looks exactly like this:
And it gets used everywhere like this:
Now what happens when I decide I want two of these? Or I decide that I want to let people create as many of these resources as possible? Or, even more commonly, what happens when I want my Consumer class to use a mocked out version of MyImportantResource? I’m scre^h^h^h^hin trouble.
The trouble comes from the fact that Consumer is reaching out into the ether and grabbing the resource it needs on its own. It isn’t giving me, the developer, control over what type of ImportantResource to use or where the ImportantResource is coming from. The Inversion of Control principle is being violated by having the class gather its own resources rather than having its creator decide and pass resources to it.
My typical solution
What I typically have been telling people is that it is OK to have a singleton, treat it as a singleton, and love the singleton pattern… within reason. At the point in your code where you’re creating all your objects and wiring them up, you should feel perfectly free to use singletons. But no layer beneath that should have any knowledge of the singleton-ness of a class. Grab that singleton and pass it into whoever needs it, preferably as an interface, and you’ve restored order and testability to your system by again returning to the Inversion of Control principle.
My DI solution
Dependency Inversion containers solve this problem for you automatically. I’ve been using Unity lately, and I’ve grown to really like it. One of the things I really like about it, and I’m sure all DI containers have this property, is that I can register a type with the container and tell it that I only want it to create a single instance of this type and pass it around whenever someone asks for that type. Bam! I have a singleton again, but I’ve completely separated the singleton-ness of the class from its singleton-like usage. Major win. Here is the code that lets me do that.
First, the interface over the important resource:
Now the changes in the MyImportantResource class to bring it back to being a regular class. Note that all mention of singleton-ness is gone from this class. Its just a plain, old class again, which is how we like it.
Next, the changes in the Consumer class that promote the loose coupling encouraged by Inversion of Control, by injecting an IImportantResource at construction:
And finally, the object construction code I can write:
The interesting bit of code here is on line 9, where I register MyImportantResource. I’m telling the container that whenever someone asks for an IImportantResource, it should give them a MyImportantResource object, and that it should give it the same instance every time (that what the new ContainerControlledLifetimeManager()) says. I’ve magically turned my MyImportantResource into a singleton class without polluting the code of that class with statics and instance methods.
Operationally nothing has changed. Assuming people always go to the container for their object instances, MyImportantResource is still a singleton. I will only have one instance of it, it is still accessible from a single place. Should I ever decide to allow 4 instances of it, I can create my own lifetime manager class that will create up to four instances and manage them for me. But now all of my classes are just that, classes. The design decision of how many instances of the resource is separated from the operation of the resource, which allows the two different design issues to evolve separately. And I’ve applied Dependency Inversion to the Consumer class, which allows it to have mock versions of the resource injected to enable testing scenarios that were more difficult when it was using the singleton.