What is Singleton pattern:
Singleton pattern allows only one class instance to exist in the application. Singleton patterns fall under the creational patterns category of GOF. Singleton pattern allows defining a class in such a way the only one instance should exist in the lifetime of the execution of the application.
Uses:
Singleton pattern can be used for the class definition for logger, configuration, caching, hardware interface and DB connection etc.
Implementation Rules:
1. Singleton pattern does not allow to create a class object using ‘new‘ keyword as below.
For example, SingletonClass single = new SingletonClass is not allowed.
Private constructor is used to restricting class to create an object using the ‘new’ keyword.
2. Singleton class should be declared Sealed as it restricts subclass of the base. Subclass might violet the pattern if the instance of subclass gets created.
3. Object of Singleton class can access through either public static property or public static method. We can write object creation logic in the property accessor method or instance method.
Differences between the singleton and static class :
Well, So with this definition it looks that we can use Static Class instead of a singleton. But both static and singleton has different purposes/intentions. Below are the differences between the singleton and static class :
1. A static class restricts to write creational logic and it’s handled by the C# compiler. Purpose of using static class is to provide the common functionality which is shared by all the classes across all the time. Whereas the singleton provides the ability to put creation logic.
2. Static class can not inherit any class or interface.
3. Static class can only have a static member which is kind of restriction.
4. Static class loaded when the application starts but singleton class can be lazily loaded.
5. Static class can not be sent as method parameter whereas singleton class can be sent as a method parameter. Because of this static class is difficult to unit tested.
Singleton pattern can be implemented in a different way such as threadsafe, without threadsafe, lazyloaded.
Flavours of Singleton pattern:
Simple Singleton: Not a threadsafe.
This below code is bad, we should avoid to use it. As this version of the singleton class is not threadsafe, hence it may violate the pattern. In this case, if two concurrent thread checks the expression “instance == null” and will be allowed to create 2 instances of the class, which is against these patterns.
Public Sealed Class SingletonCls
{
Private static SingletonCls instance = null;
Private Singleton()
{
// This private constructor restrict a user to create an instance using 'new' keyword
}
Public static SingletonCls GetInstance()
{
if(instance == null)
{
instance = new SingletonCls();
}
return instance;
}
}
Threadsafe Singleton :
We need to add lock object to the singleton class instance to make it threadsafe so that it can handle concurrent thread request without interfering each other.
Private SingletonCls()
{
// This private constructor restrict the user to create
// an instance using 'new' keyword
}
Public static SingletonCls GetInstance()
{
Lock(lockobj)
{
if(instance == null)
{
instance = new SingletonCls();
}
return instance;
}
}
}
Singleton: Fully lazy initialization
Public sealed class SingletonCls
{
Private static readonly Lazy lazyObj = new Lazy(() => new SingletonCls());
Private SingletonCls(){}
Public static SingletonClsGetInstance()
{
return lazyObj.Value;
}
}
Conclusion:
So, the 1st version certainly should be avoided as it violates the pattern and can create a race condition. Also in most cases, we only need the lazy-loaded version when we have several tasks to be done in the constructor. So, if we can go with the early version of singleton implementation until we need it specifically.