The Creational Design Pattern is most commonly used in software design. It is deal with the object creation. The basic form of object creation could result in a design problem or added complexity to the design. In short a Creational Design Pattern states how an object is created when it is created. All programming languages that supports objects may access them globally, which means an object can have a global scope. There are also some cases in object-oriented systems in which it should be only one class or fixed number of instances of a class at the given time.
At first glance, one might be excited to create a static class to resolve the problem described above, but static classes are instantiated at runtime. In other words, a static class is loaded when the program that references the class is loaded. This could be a time consuming process.
So an alternative solution is a Singleton class.
The purpose of the Singleton is to control object creation, limiting the number to one but allowing the flexibility to create more objects if the situation changes. Since there is only one Singleton instance, any given time, a Singleton will occur only once per class, just like static fields.
Advantages of a Singleton pattern:
- Singleton pattern can be implemented interfaces.
- It can be also inherit from other classes.
- It can be lazy loaded.
- It has Static Initialization.
- It can be extended into a factory pattern.
- It help to It hide dependencies.
- It provides a single point if access to a particular instance, so it is easy to maintain.
Disadvantages of a Singleton Pattern
- Unit testing is more difficult (because it introduces a global state into an application).
- This pattern reduces the potential for parallelism within a program, because to access the singleton in a multi-threaded system, an object must be serialized (by locking).
Singleton class vs. Static methods
- A Static Class cannot be extended whereas a singleton class can be extended.
- A Static Class can still have instances (unwanted instances) whereas a singleton class prevents it.
- A Static Class cannot be initialized with a STATE (parameter), whereas a singleton class can be.
- A Static class is loaded automatically by the CLR when the program or namespace containing the class is loaded.
Implementation
The singleton pattern is one of the most popular design patterns in software industries. Basically, a singleton is a class which only allows creation of a single instance of it (the class) and gives simple access to that instance.
There are various ways to implementing the Singleton Pattern in C#. The following are the common characteristics of a Singleton Pattern.
- A single constructor, which is private and parameterless. This will prevent creation of an instance of the class.
- The class is sealed.
- A static variable which holds the reference of the created instance.
- Public static methods.
There are many way to implement a Singleton Pattern in C#.
- No Thread Safe Singleton
public sealed class NoThreadSafeSingleton
{
static NoThreadSafeSingleton instance = null;
NoThreadSafeSingleton()
{
}
public static NoThreadSafeSingleton Instance
{
get
{
if (instance == null)
{
instance = new NoThreadSafeSingleton();
}
return instance;
}
}
public static string GetProjectName()
{
return "No Thread Safe Singleton";
}
}
In the above code, when two threads are executed, it always finds an instance which is null which is a violation of the singleton pattern. In fact the instance may already have been created before the expression is evaluated, but the memory model doesn't recognize that the new value of the instance will be seen by other threads.
- Thread-Safety
public sealed class ThreadSafetySingleton
{
static ThreadSafetySingleton instance = null;
static readonly object padlock = new object();
ThreadSafetySingleton()
{
}
public static ThreadSafetySingleton Instance
{
get
{
lock (padlock)
{
if (instance == null)
{
instance = new ThreadSafetySingleton();
}
return instance;
}
}
}
public static string GetProjectName()
{
return "With Thread Safe Singleton";
}
}
In the above code, the thread is locked on a shared object and checks whether an instance has been created or not. This will ensure that only one thread creates an instance. The biggest problem with this is performance; performance suffers since a lock is required every time an instance is requested.
- Thread-Safety using Double-Check Locking
public sealed class ThreadSafetyDoubleCheckLockingSingleton
{
static ThreadSafetyDoubleCheckLockingSingleton instance = null;
static readonly object padlock = new object();
ThreadSafetyDoubleCheckLockingSingleton()
{
}
public static ThreadSafetyDoubleCheckLockingSingleton Instance
{
get
{
if (instance == null)
{
lock (padlock)
{
if (instance == null)
{
instance = new ThreadSafetyDoubleCheckLockingSingleton();
}
}
}
return instance;
}
}
public static string GetProjectName()
{
return "Thread Safety Double Check Locking Singleton";
}
}
In the above code, the thread is locked on a shared object and checks whether an instance has been created or not with double checking.
- Thread-safe without using locks and no lazy instantiation
public sealed class ThreadsafewithoutLockSingleton
{
static readonly ThreadsafewithoutLockSingleton instance = new ThreadsafewithoutLockSingleton();
static ThreadsafewithoutLockSingleton()
{
}
ThreadsafewithoutLockSingleton()
{
}
public static string GetProjectName()
{
return "Thread safe without Locking Singleton";
}
public static ThreadsafewithoutLockSingleton Instance
{
get
{
return instance;
}
}
}
The above implementation looks like very simple code. This type of implementation has a static constructor, so it executes only once per Application Domain. It is not as lazy as the other implementation.
- Fully lazy instantiation
public sealed class FullyLazyInstantiationSingleton
{
FullyLazyInstantiationSingleton()
{
}
static FullyLazyInstantiationSingleton Instance
{
get
{
return ActualSingleton.instance;
}
}
public static string GetProjectName()
{
return "Fully Lazy Instantiation Singleton";
}
class ActualSingleton
{
static ActualSingleton()
{
}
internal static readonly FullyLazyInstantiationSingleton
instance = new FullyLazyInstantiationSingleton();
}
}
In the above code, instantiation is triggered by the first reference to the static member of nested classes which only occurs in one instance. In other words implementation is fully lazy. The code is more complicated in order to make the instantiation lazy.
Conclusion
The Singleton Design Pattern is a very useful mechanism for providing a single point of object access in an object-oriented application. There are many other different ways of implementing the singleton pattern in C#. It depends on situations where you use which type of implementation. Generally people select either method 4 or 5 to implement a singleton pattern.