Stories about Software


One Singleton to Rule Them All

I would like to preface this post by saying that I don’t like the Singleton design pattern at all. There are some who love it, others who view it as a sometimes-useful, often-abused tool in the toolbox, and then there are people like me who believe that it’s extremely rare to see a use of it that isn’t an abuse — so rare that I consider it better to avoid the pattern altogether. I won’t go into much more detail on my thoughts on the Singleton (stay tuned for that when I get to this pattern in my design patterns series), but here is some further reading that expounds a lot on reasons not to like this pattern:

  1. Scott Densmore: Why Singletons are Evil
  2. Misko Hevery: Singletons are Pathological Liars
  3. Alex Miller: Patterns I Hate
  4. Steve Yegge: Singleton Considered Stupid

With all of those arguments against Singleton in mind, and considering the damage that abuse (and I would argue use) of the pattern causes in code bases, I found myself thinking of code bases I’ve heard of or encountered where the code was littered with Singletons. In these code bases, refactoring becomes daunting for a variety of reasons: the hidden dependencies, the complex temporal dependencies, the sheer volume of references to the Singleton instances, the almost obligatory Law of Demeter violations, etc. Singletons cause/encourage a rich variety of problems in code bases. But I think that something could be done about two such problems: the redundant Singleton implementation logic and the Single Responsibility Principle (SRP) violation of which Singleton classes are prima facie guilty.

Take a look at how the Singleton is implemented (as recommended by Microsoft, here). The basic implementation initializes the static instance in the property accessor while variants use field initializing syntax and introduce thread safety.

The basic implementation is here:

More specific even to C# is James Michael Hare’s implementation using the Lazy<T> class to eliminate the redundant if-instance-null-instantiate logic needed in each Singleton class. But that still leaves the redundant Instance property, the redundant _instance field, and the awkwardness (SRP violation) of an object managing its own cardinality. What if we got rid of both of those issues?

Using generics, this implementation allows an instance of every Singleton to be expressed in the code of a single class. In this fashion, any type can be implemented as a Singleton without the type being coupled to an internal Singleton implementation. It also standardizes the Singleton implementation by making sure it exists only once in the code base. With this pattern, there is a similar feel to IoC containers — classes can be implemented without concern for who will instantiate them and how.

Here is my take on the disadvantages and potential disadvantages of this approach:

  1. You still have Singletons in your code base.
  2. This might actually encourage more Singleton usage (though fewer actual Singleton implementations) by removing responsibility for implementation.
  3. Since constructor of object in question must have public default constructor, removes the Singleton gimmick of making the constructor private and thus the safeguard against additional instances being created is also removed.
  4. A natural extension of the previous item is that it remains a matter of documentation or convention to use Singleton<T> and not instantiate rather than it being impossible to instantiate.

But the advantages that I see:

  1. Only one class implements cardinality management, meaning refactoring away from Singleton is nominally easier.
  2. No Singleton SRP violations
  3. Singleton implementation (initialization, lazy load, thread-safety) is standardized to prevent inconsistent approach.
  4. I actually consider preventing the private constructor gimmick to be a plus — particularly where potential refactoring may be needed (and it pretty much always is when Singletons exist).
  5. With this pattern in your code base developers are less likely to be come comfortable/familiar with implementing the Singleton pattern.
  6. No need to introduce interfaces for Singletons to inject instance into classes using dependency injection — just inject a non-Singleton managed instance.
  7. A code base with nothing but normal instances is very easy to reason about and test, so the closer you get to that, the better.

I would like to reiterate that I’m not suggesting that you run out and start doing this everywhere. It mitigates some of the natural problems with the Singleton design pattern but “mitigates some” is a long way from “fixes all”. But, if you have a code base littered with Singletons this could potentially be a nice intermediate refactoring step to at least standardize the singleton implementation and provide slightly more friendly seams to testing legacy code. Or if you’re faced with and outvoted by a group of other developers that love their global variables (er, excuse me, Singletons), this might be a decent compromise to limit the damage they cause to the code’s maintainability. On balance, I’d say that this is an interesting tool to add to your arsenal, but with the caveat that something is probably wrong if you find that you have a use for it.

I’d be curious to hear others’ takes on this as well. I just kind of dreamed this up off the top of my head without taking a lot of time to explore all potential ramifications of it use. If you’ve implemented something like this before or if you have opinions on the advantages/disadvantages that are different than mine or if you see ways it could be improved, I’d be interested to hear about it in the comments.

  • memosk

    What is a SINGLETON ?: It is functional programing .

    If you can’t use object programming then you use a Singleton .
    It is normal that some new programmers or sometimes it is about lack of ANALITIC abilities of programmer, nor they are stupid 😉 , They use Singleton.

    SINGLETON is not general violation of Agile programming . But you shouldn’t use it–>: If yoy got some problems with it .

    THEN : You have to (!!) re-program it. How it is “writen” in agille approach.

Acknowledgements | Contact | About | Social Media