25 March 2016

tl;dr Patterns, 20 Years Later: Let's start with everybody's favorite (and most despised) pattern, the Singleton. Everybody loves the Singleton because, conceptually, it seems the easiest of the lot to understand and (in most post-1995 languages) the easiest to implement. But everybody hates it because its singleton-y nature means it is a natural target for concurrency problems up the wazoo. (And then there's that whole "Singleton instance vs static methods" debate that goes on.)


We want to ensure only one instance of a given type, and provide a global point of access to it.


"There must be exactly one instance of a class, and it must be accessible to clients from a well-known access point." For whatever domain reason, we must have exactly one instance of a given type. (Typically, in a class-based language like Java/C#/C++, this means one instance of a given class type.) This instance should be accessible from anywhere in the codebase, but because we generally want to retain some level of encapsulation over this instance, there should be some level of indirection or access control to the instance, so that we have the ability to change/evolve/refactor.

When the sole instance should be extensible by subclassing, and clients should be able to use an extended instance without modifying their code. One of the interesting subtexts around Singleton, as mentioned above, is that whole "instance vs statics" debate: When does a Singleton make sense, as opposed to just a set of statics (methods/properties/fields)? If there is some need/desire to subclass the Singleton type, then the discussion becomes much clearer (although there are a few languages in which static methods can be "overridden" in derived classes, which brings the discussion back again.)


Provide some global/static access entity to obtain that single instance.

Some interesting questions come up when implementing a Singleton:

Some of these are explored in the implementation examples.

Note that some solutions seek to have singleton-ness imposed externally, by wrapping an object instance into a mechanism that "transforms" the object instance into a Singleton. This approach usually cannot enforce Singleton-ness on its own (somebody had to create one, so that means others are able to create one), except in some languages where the object's definition doesn't need to be known in order to use it (a la an interface/implementation split in Java or C#, or using a dynamically-resolved language like Ruby or Javascript). These provide an easy way to put an object into a "known location" (making it more easily accessible from wider contexts---or from any context, as the desire may be), but lacks the ability to enforce the Singleton-ness that Singleton usually stresses.



Singleton yields the following:


A Singleton that takes a String or some other key as a parameter in its instance-accessing method is often called a Registry; generally the context there changes from "ensure only one instance of this object" to "ensure only one instance of this object, as well as any other object accessible via a key lookup". (If the Registry gets too large or too complicated, it usually turns into a database.)

Many systems took the Singleton and stretched it across multiple processes in a distributed system. This resulting Distributed Singleton usually caused nothing but pain and suffering to the system once it started to scale up (and often long before then). To be avoided at almost any cost. (There may be a very few edge cases where a Distributed Singleton is useful, but the bar should be very high when thinking about using it.)