Creational Patterns: Singleton Flashcards
What is a singleton?
A class designed to only ever have one instance. The class itself is responsible for enforcing this design requirement.
What are the three most common use cases of the Singleton?
- Access to file system (shared instance)
- Access to shared network resource (shared instance)
- When one-time configuration is expensive
What is the structure of the Singleton?
A single class with a private instance and a public static method that provides the only way to reference that instance. It must also have a private constructor.
What can be said about the number of instances of a class that implements the Singleton.
They have, at any time in the life of an application, either 0 or 1 instance.
What can be said about the parameters needed to instantiate a Singleton class?
Singleton classes are created without parameters.
When does a Singleton instance get created?
By default, when something requests them (lazy instantiation). However, it is also possible to simply create the instance you need when the application starts and then use that instance for the life of the app.
What can be said about the constructor of the Singleton classes and what does this imply?
Singleton classes should have a single, private, parameterless constructor. Because of this, subclassing is not allowed.
What can be said about inheriting a Singleton class?
Singleton classes should be marked as sealed. Therefore, they cannot be inherited.
What can be said about the referencing a Singleton class?
A private static field holds the only reference to the instance. A public static method provides access to this field.
What is the biggest problem with the naive implementation of the Singleton?
It is not thread safe.
In multithreaded environments, multiple threads can invoke a call to the constructor by accessing the Instance
property/method.
What is the most basic and obvious way to achieve thread safety for the Singleton?
To use a private padlock ‘object’ field and a lock
block around the logic in the Instance getter.
get { lock (_padlock) return _instance ??= new(); }
What’s the drawback of using a lock statement and an object
as the lock?
It has negative performance impacts because every use of the Instance
property will incur the overhead of the lock.
If you were to use locks, what should you use as the lock object?
A dedicated private instance variable. Lock statements should be paired one to one with their lock variables.
What is a simple way to improve the performance of a basic thread-safe Singleton that uses a lock?
To perform a null check on the instance before the lock statement.
get { if (_instance is null) lock (_padlock) _instance ??= new(); return instance; }
What is the downside of using a lock to achieve thread safety in a singleton?
The most basic approach where we simply lock and return a new instance or the existing instance calls the lock statement in every call to the Singleton. This is bad for performance.
The double-checking approach where we check whether the instance is null before the lock statement is complex, easy to get wrong and doesn’t necessarily work with the ECMA common language interface specification.