The singleton pattern is one of the best-known patterns in software engineering. In a singleton pattern, we ensure that the class has only one instance and we provide a simple and global point of access to this object. This is useful when we require exactly one object of a class to perform our operations.
Singleton classes don't allow any parameters to be specified when creating the instance because a second request for an instance but with a different parameter could be problematic.
In this article, I'll provide you with a real-time example, a Comparison of Singleton with Static class, a UML class diagram of Singleton, and then the implementation of Singleton in various ways.
Real-time example:
The practical implementation of the Singleton design pattern can be seen in various applications used by us. Take the example of Microsoft word, there is only one instance of the word application active at a time even though the user opened multiple documents at a time. And all the requests for different word documents are handled by a single instance.
Singleton versus Static Class:
Singletons and Static classes both provide sharing of redundant objects in memory, but they differ in usage and implementation. Mentioned below are some points one should consider before making a decision:
- Singletons preserve the conventional class approach and don't require that you use the static keyword everywhere, while static class requires all members should be static.
- Singleton may be more demanding to implement at first, but will greatly simplify the architecture of your application as compared to static class.
- Singleton requires a single private and parameter-less constructor, while a static class can only have a static constructor.
- Unlike static classes, one can use a singleton as a parameter to methods, or objects.
- In the case of the Singleton class, there should be at most one object through which we can access the class members, while in the case of the Static class we needn't any object to access class members.
- Singleton object is created lazily, i.e. the instance isn't created until it is first needed. On the other hand, the static class is loaded into memory as soon as the application is initialized.
UML class diagram
UML class diagram for the Singleton pattern is given below.
Implementation:
In the case of the Singleton pattern, there is a single private and parameter-less constructor. This prevents other classes from instantiating it. It also prevents subclassing because if a singleton can be subclassed and if each of those subclasses can create an instance that means a violation in the pattern. Other than that there is a static variable (or we can have a method as well) that holds a reference to the single created instance. And on top of that a public static means of getting the reference to the single created instance.
Here we'll see different ways of implementing the singleton pattern in C#.
A simple version of Singleton:
It is not thread-safe, i.e. two different threads may create two instances.
/// <summary>
/// Bad way to
implement Singleton
/// </summary>
public class
Singleton
{
private static Singleton
_instance = null;
private
Singleton()
{
}
public static Singleton
Instance
{
get
{
if
(_instance == null)
{
_instance = new Singleton();
}
return
_instance;
}
}
}
|
Singleton with simple thread safety:
In this implementation, the lock is added to make Singleton thread-safe. In this case, the thread takes out a lock and then checks if the instance already exists or not before creating the new instance. This ensures that only one thread will create an instance as only one thread can be in that part of the code at a time - by the time another thread enters, the first thread will have created the instance. But there is a performance overhead as a lock is acquired every time the instance is requested.
/// <summary>
/// Singleton with
thread safety
/// </summary>
public class
Singleton
{
private static Singleton
_instance = null;
private static readonly object synclock = new
object();
private
Singleton()
{
}
public static Singleton
Instance
{
get
{
lock
(synclock)
{
if
(_instance == null)
{
_instance = new Singleton();
}
return
_instance;
}
}
}
}
|
Singleton with thread-safety using double-checks locking:
This implementation attempts to be thread-safe along with avoiding taking a lock every time.
/// <summary>
/// Singleton with
thread safety using double check
/// </summary>
public class
Singleton
{
private static Singleton
_instance = null;
private static readonly object synclock = new
object();
private
Singleton()
{
}
public static Singleton
Instance
{
get
{
if
(_instance == null)
{
lock
(synclock)
{
if
(_instance == null)
{
_instance = new Singleton();
}
}
}
return
_instance;
}
}
}
|
Singleton with thread safety without using locks:
This is another version of thread-safe Singleton, but without using locks. This implementation is faster than adding extra checking as in the above example. But this implementation is not as lazy as the other implementations (as we are using a static constructor).
/// <summary>
/// Thread safe
Singleton without lock
/// </summary>
public class
Singleton
{
private static readonly Singleton _instance = new
Singleton();
/// <summary>
/// Explicit static constructor to tell C# compiler
/// not to mark type as beforefieldinit
/// </summary>
static
Singleton()
{
}
private
Singleton()
{
}
public static Singleton
Instance
{
get
{
return
_instance;
}
}
}
|
Singleton with full lazy instantiation:
To fix the problem mentioned in the above example, we can modify the code and create a private class inside the Singleton class and that'll allow full lazy instantiation along with all the performance benefits.
/// <summary>
/// Thread safe
Singleton with full lazy instantiation
/// </summary>
public class
Singleton
{
private
Singleton()
{
}
public static Singleton
Instance
{
get
{
return
Nested._instance;
}
}
private class Nested
{
/// <summary>
/// Explicit static constructor to tell C# compiler
/// not to mark type as beforefieldinit
/// </summary>
static
Nested()
{
}
internal
static readonly
Singleton _instance = new Singleton();
}
}
|
Singleton with .Net Lazy<T>:
If you're implementing Singleton in .NET 4.0 (or higher versions), you can use the System.Lazy<T> type to make the lazy instantiation. You can easily write the code with the help of lambda expression and you just need to pass a delegate to the constructor which calls the constructor of the Singleton class. It's easy to write and understand and also performs well. You can also use the IsValueCreated property (in the .Net 4.5 frameworks) to check whether or not the instance has been created yet.
/// <summary> /// Singleton with Lazy<T> /// </summary> public class
Singleton { private static readonly Lazy<Singleton>
lazy = new Lazy<Singleton>(() => new
Singleton()); private
Singleton() { } public static Singleton
Instance { get { return
lazy.Value; } } } |
Comments
Post a Comment