Singleton Pattern
Classic GOF Constructional Design Patterns
Intent
The singleton pattern is a design pattern that restricts the instantiation of a class to one object.
It is used when:
- Ensuring that a class has one and only one instance, and provide a global point of access to it.
- Encapsulating "just-in-time initialization" or "initialization on first use" and then enabling re-use of the object.
- Creating an object that is designed to be reused over and over again that is expensive to create and also requires a single shared instance.
Problem
Sometimes it's important to have only one instance for a class. For example, in a application you might want to ensure that there should be only one database connection (or only a single settings or configuration object). Usually singletons are used for centralized management of internal or external resources and they provide a global point of access to themselves.
Discussion
The singleton pattern is one of the simplest design patterns: it involves only one class which is responsible to instantiate itself, to make sure it creates not more than one instance; in the same time it provides a global point of access to that instance. In this case the same instance can be used from everywhere and should only be accessible from a single place.
Singleton's allow us to have only a single instance of the object throughout the life-cycle of the application. Why would that be important? Because first, you don’t want to create more than one heavy resource consuming objects when you really want only one. Second, sometimes, not only creating more than one instance is costly, it can take you to inconsistent state. For example, you wouldn’t want to have multiple database or settings objects because changes in one, may make others inconsistent. Singletons also reduce the need for global variables which is particularly important in languages such as JavaScript because it limits namespace pollution and associated risk of name collisions. Several other patterns, such as, Factory, Prototype, and Façade are frequently implemented as Singletons when only one instance is needed.
Singletons should be considered only if all three of the following conditions are required:
- Ownership of the single instance cannot be reasonably assigned
- Lazy initialization is desirable
- Global access is not otherwise provided for
It should be noted that Singletons are often misused when they are not required. They are also often implemented incorrectly or not completely - especially when dealing with multi-threading situations.
Structure
There are various different ways of implementing the singleton pattern - typically; however many of them are challenged in one way or another. Here we will discuss a fully lazily-loaded, thread-safe, simple and highly performant version.
All Singleton implementations share four common characteristics, however:
- A single constructor, which is private and parameterless. This prevents other classes from instantiating it (which would be a violation of the pattern). Note that it also prevents sub-classing - if a singleton can be sub-classed once, it can be sub-classed twice, and if each of those sub-classes can create an instance, the pattern is violated. The factory pattern can be used if you need a single instance of a base type, but the exact type isn't known until run time.
- The class is sealed - where supported by the programming language choice.. This is unnecessary, strictly speaking, due to the above point, but may help the JIT to optimize things more.
- A static variable which holds a reference to the single created instance, if any.
- A public static means of getting the reference to the single created instance, creating one if necessary.
As one of the most basic design patterns, this is about as simple as it gets. The Singleton contains a private static object that is completely inaccessible from outside. This object can only be accessed via the getInstance() static method.
Practical Example
As stated in the STRUCTURE discussion above, the Singleton is one of the most fundamental and basic design patterns. >For our purposes, lets choose using a singleton to create and provide access to an expensive resource - a database connection.
Code Samples
Below, you will find examples of the Singleton Pattern implemented in four different commonly used languages. Each one of the examples implements the exact same scenario as described in the PRACTICAL EXAMPLE section above.
Each sample will use a singleton pattern to create and return an expensive database connection object.
C# Singleton Code Sample
In this C# example, we take advantage of a number of features of the .NET platform that make this extremely simple to implement. The version provided here is highly performant, if not perfectly lazy-loaded. It is a compromise.
It is possible to extend this sample to also include perfect lazy loading; however, the code becomes much more complex and typically involves locking. For most practical situations where the class is responsible for only returning a single type instance, this performs outstanding. It will prematurely load the instance only in scenarios if there are other things going on with the class (probably not a great idea in any case).
Java Singleton Code Sample
In this Java example, we take a page from a Java expert.
Prior to Java 5, the java memory model had a lot of issues and many approaches used to fail in certain scenarios where too many threads try to get the instance of the Singleton class simultaneously. So Bill Pugh came up with a different approach to create the Singleton class using an inner static helper class. The Bill Pugh Singleton implementation goes like this;
Typescript Singleton Code Sample
In this TypeScript example, it is again about as basic as it can get.
JavaScript Singleton Code Sample
In this JavaScript example, The Singleton object is implemented as an immediate anonymous function. The function executes immediately by wrapping it in brackets followed by two additional brackets. It is called anonymous because it doesn't have a name.
The getInstance method is Singleton's gatekeeper. It returns the one and only instance of the object while maintaining a private reference to it which is not accessible to the outside world.
The getInstance method demonstates another design pattern called Lazy Load. Lazy Load checks if an instance has already been created; if not, it creates one and stores it for future reference. All subsequent calls will receive the stored instance. Lazy loading is a CPU and memory saving technique by creating objects only when absolutely necessary.
Considerations
- Define a private static attribute in the "single instance" class.
- Define a public static accessor function in the class.
- Do "lazy initialization" (creation on first use) in the accessor function.
- Define all constructors to be protected or private.
- Clients may only use the accessor function to manipulate the Singleton.
Additional Notes
- Abstract Factory, Builder, and Prototype can and often do use Singleton in their implementation.
- Facade objects are often Singletons because only one Facade object is required.
- State objects are often Singletons.
- The advantage of Singleton over global variables is that you are absolutely sure of the number of instances when you use Singleton, and, you can change your mind and manage any number of instances.
- The Singleton design pattern is one of the most inappropriately used patterns. Singletons are intended to be used when a class must have exactly one instance, no more, no less. Designers frequently use Singletons in a misguided attempt to replace global variables. A Singleton is, for intents and purposes, a global variable. The Singleton does not do away with the global; it merely renames it
- When is Singleton unnecessary? Short answer: most of the time. Long answer: when it's simpler to pass an object resource as a reference to the objects that need it, rather than letting objects access the resource globally. The real problem with Singletons is that they give you such a good excuse not to think carefully about the appropriate visibility of an object. Finding the right balance of exposure and protection for an object is critical for maintaining flexibility.