Singleton
Before moving to the Singleton Design Pattern, let's first understand what a singleton is.
Singleton allows creating only one object to a class and this class restricted to one instance provides a global point of access to it.
Advantages
The advantages of a Singleton Pattern are,
- It supports lazy loading.
- Support of Static Initialization.
- It has a single point of access to a particular instance and it is very easy to maintain.
Disadvantages
This pattern does not support parallelism within a program because there is no multi-threaded system access in the singleton pattern and an object must be serialized by locking.
Singleton class vs. Static methods
The following points compare the Singleton class vs. Static methods,
- A Static Class cannot be extendable whereas a singleton class can be extended.
- A Static Class is able to instantiate but a singleton class prevents it.
- Singleton supports STATE initialization whereas Static Class not.
- When program or namespace containing the class is loaded, the static class is loaded automatically by the CLR.
Implementation of the singleton design pattern class
The following code is for a thread-safe implementation of the singleton pattern.
Implementation of the Singleton Design Pattern
First version - not thread-safe,
-
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- namespace ConsoleApplication {
- publicsealedclass SingletonClass {
-
- privatestatic SingletonClass _instanceSingleton = null;
-
- private SingletonClass() {}
- publicstatic SingletonClassInstance {
- get {
- if (_instanceSingleton == null) {
- _instanceSingleton = new SingletonClass();
- }
- return _instanceSingleton;
- }
- }
- }
- }
This is not thread-safe. Becuase it voilates the singleton pattern when two different threads could both have evaluated the test if (_instanceSingleton==null) and found it to be true, then both create instances.Factually the instance may be created already before the expression is evaluated, but the memory model doesn't guarantee that the new value of instance other threads can see unless suitable memory pass.
Thread-safety using double-check locking
Singleton Class
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- namespace ConsoleApplication {
- public sealed class SingletonClass: IDisposable {
- private static volatile SingletonClass _instanceSingleton = null;
- private static readonly Object _tryLock = new object();
- public int counter = 0;
- private SingletonClass() {}
- public static SingletonClass singletonClass {
- get {
- if (_instanceSingleton != null) return _instanceSingleton;
- lock(_tryLock) {
- if (_instanceSingleton == null) {
- _instanceSingleton = new SingletonClass();
- }
- return _instanceSingleton;
- }
- }
- }
- public void writeSignature() {
- Console.WriteLine("Singleton function {0}", counter);
- this.Dispose();
- }
- public void Dispose() {
- GC.SuppressFinalize(this);
- }
- }
- }
Main Program Class
Test the implemention of the Singleton Class in Main Program Class,
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- namespace ConsoleApp1 {
- public class Program {
- private staticvolatile Program _progInstance;
- public static Program progInstance {
- get {
- if (_progInstance == null) _progInstance = new Program();
- return _progInstance;
- }
- }
- public void run() {
-
- SingletonClass singClassTwo = SingletonClass.singletonClass;
-
- SingletonClass singClass = SingletonClass.singletonClass;
-
- singClassTwo.writeSignature();
- singClassTwo.counter++;
-
- singClass.writeSignature();
- singClass.counter++;
- Console.Read();
- }
- static void Main(string[] args) {
- progInstance.run();
- }
- }
- }