As a preparation for an upcoming workshop on design patterns, I revisited some of the more common design patterns. The most infamous one is probably the singleton pattern. Lauded by some, called an ugly mask for global variables by others, it certainly seems to divide the community. I, too, am "guilty" of its use.

As a quick refresher: The singleton pattern refers to a software design pattern in which you enforce that there is but one instance of a certain class. A somewhat contrived usage example might be an application that has a central manager that is queried about the state of its objects.

Disadvantages

So, what are the disadvantages of this pattern? On the surface, singletons appear to be useful and rather easy to implement, there are hidden depths. First of all, making a singleton thread-safe is no easy task. There is a whole paper, written by none other than Scott Meyers and Andrei Alexandrescu, two very prominent figures of the C++ pantheon, next only to the mighty Stroustroup himself. Furthermore, it is not easy to guarantee that only one singleton will be created all the time. For example, when using templates in C++, a templated singleton class might be instantiated for every compilation unit. Also, if different threads vie for control over the singleton instance, one needs to look out for race conditions (although to be honest, this is the whole "singletons are not thread-safe issue" all over again). Last, I dislike that the singleton pattern somewhat favours tight coupling between different classes. Since the singleton cannot be changed at runtime, all dependent classes are bound to use it. Thus, the singleton instance contains a lot (perhaps too much) state information that lasts over the complete life-time of the program.

Advantages

So, why use singletons then? When I created one the last time, I thought that the singleton at least shows the intent that there should only be one instance of something. For example, if the rest of your application depends on a class that manages data, there better only be one instance of the data manager. Or else...

Also, the singleton offers a great way for providing a single point of access towards objects or methods. I could, for example, enforce that a singleton data manager is locked until a dependent class has finished its operation. This leads to (at least in my opinion) cleaner code and less battles about shared resources.

An alternative?

Still, the fact that a singleton is basically a global variable in a fancy dress somehow got to me. Insight came to me one day: Each dependent class (i.e. each class that uses the singleton for some operation) is not really interested in knowing that there is only one global instance of the singleton. The class is only interested in knowing which object needs to be interacted with in order to perform the operation.

Again, a slightly contrived example. Suppose we have a game engine with classes for different creatures. Each creature instance is not interested in whether there is a single global map on which it appears. Rather, it only needs to know which particular map instances it is a part of. Thus, we could create a constructor for each creature that requires a pointer to the map class:

Creature::Creature( Map* map )
  : map_( map )
{
}

And later on, we could simply peruse "our" map instance for all operations:

bool Creature::canAttack( Creature* other )
{
  return map_->isInRange(this, other);
}

What I immensely liked about this idea was that I do not need to ensure that there is only a single instance of the map class. Rather, I could create one instance of the map class prior to starting any other threads and simply use them for all dependent objects.

So, what are the advantages of this method? First, this completely circumvents thread problems. If needed, every method of the map class could use a mutex to ensure that only one thread is currently using it. But what I like even more is the idea that the implementations are now slightly exchangeable. If the map class becomes an abstract base class, we could simply use all sorts of wacky map implementations for the creature class—a map that measures distances on the torus, for example. If this sounds too contrived to you, let me put it more abstractly: By using only a pointer at the class constructor, we can swap out implementations (for testing purposes) and make the coupling between classes more loose.

Conclusion—nothing new under the sun

I thought I had come up with a great new way of combining the power of singletons with my personal guidelines for clean code. Imagine my shock when I discovered that this technique is known as dependency injection. Well, I tried.

Let me end this on a positive note: I do not think that the singleton pattern is necessarily "evil" or "wrong". It just seems very easy to abuse or use incorrectly. Writes the guy who at one time thought that singletons were the best invention since sliced bread.

Posted Sunday evening, August 24th, 2014 Tags: