September 6, 2007

...Learn TDD with Codemanship

Singletons Done Safely

What joy.

Today I am doing code reviews.

First thing that jumps out at me in the project I'm looking at is the liberal use of what the developers refer to as "singletons".

Many learned folk will tell you that singletons are dangerous, from a design quality perspective. But I think we're mixing our matadors a little here: it's not singletons, per se, that are dangerous. It's global variables disguised as singletons that do the actual harm.

The problem is the way we implement singletons in most OO programming languages.

Typically, we have to declare a class which has a private constructor, so only it can create an instance of itself, and then we have a creator/accessor method - a factory - that passes back the one instance of that class. If no instance exists, it creates it. Otherwise it just passes back the already created instance. There is only one slot in the whole system for an instance of that class. Hence, it is a "singleton".

But to do this in, say, C#, we traditionally declare that one slot as a static member variable. And we declare our creator/accessor method as static, too.

And this is where it can get a little sucky. You see, public static variables can be accessed from any other class that it's visible to - which can be a lot of classes.

These are effectively globally accessible variables (even when their being accessed through static accessor methods). The bad practice is to build in the knowledge of how to access the singleton everywhere that it's used. That tends to lead to a lot of dependencies that could have been avoided. It also makes it impossible to abstract or invert these dependencies, which means we're stuffed, from an OO design perspective. we might as well be using old-fashioned VB modules.

But let's not throw the baby out with the bathwater. Global variables are bad. But singletons are useful. Can we find a way to implement a singleton and avoid the bear trap?

I think so, yes. One way to do this is to have the static creator/accessor method used in only one place, and then references to the singleton can be passed as method parameters or in constructors. This is a matter of discipline, of course. You must choose not to use the creator/accessor anywhere else in the code.

So, that's my tuppence-worth: singletons are not necessarily bad if you use them with discipline.

And it occurs to me - for any refactoring tool developers who might be reading this - that it wouldn't be fantastically difficult to automatically replace Singleton.GetInstance() with a suitably-named variable - maybe offering a choice of passing it in as a method parameter, or storing it as a field and passing it into the constructor.
Posted 13 years, 3 months ago on September 6, 2007