Singleton Design Pattern

From JholJhapata
Revision as of 18:29, 10 December 2019 by Admin (talk | contribs) (→‎Example)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

The singleton pattern is a software design pattern that restricts the instantiation of a class to one single instance. This is useful when exactly one object is needed to coordinate actions across the system.

Singleton

Problem

If we have some resource that can only have a single instance and you need to manage that single instance that is where Singleton Pattern plays important role. For Example, logger classes , driver object classes etc.

Example

Let’s take a look at an example, which is creating multiple objects.

   class Program
   {
       static void Main(string[] args)
       {
           SingleTon obj1 = new SingleTon();
           obj1.printText("obj1");
           SingleTon obj2 = new SingleTon();
           obj2.printText("obj2");
           Console.WriteLine("Main End");
           Console.ReadLine();
       }
   }
   class SingleTon
   {
       private static int objectCounter = 0;
       public SingleTon()
       {
           objectCounter++;
           Console.WriteLine("objectCounter : " + objectCounter.ToString());
       }
       public void printText(string strData)
       {
           Console.WriteLine(strData);
       }
   }

Output

   objectCounter : 1
   obj1
   objectCounter : 2
   obj2
   Main End

We created 2 object for printing text log.

Solution

The common characteristics of a Singleton Pattern:

  • A single constructor, that is private and parameter-less.
  • The class is sealed.
  • A static variable that holds a reference to the single created instance, if any.
  • A public static means of getting the reference to the single created instance, creating one if necessary.

First version - not thread-safe

   class Program
   {
       static void Main(string[] args)
       {
           SingleTon obj1 = SingleTon.getInstance;
           obj1.printText("obj1");
           SingleTon obj2 = SingleTon.getInstance;
           obj2.printText("obj2");
           Console.WriteLine("Main End");
           Console.ReadLine();
       }
   }
   class SingleTon
   {
       private static int objectCounter = 0;
       private static SingleTon instance;
       private SingleTon()
       {
           objectCounter++;
           Console.WriteLine("objectCounter : " + objectCounter.ToString());
       }
       public static SingleTon getInstance
       {
           get
           {
               if(instance == null)
                   instance = new SingleTon();
               return instance;
           }
       }
       public void printText(string strData)
       {
           Console.WriteLine(strData);
       }
   }

Output

   objectCounter : 1
   obj1
   obj2
   Main End

Problem 1

Example
   class Program
   {
       static void Main(string[] args)
       {
           System.Threading.Tasks.Parallel.Invoke(
               () => obj1Fn(),
               () => obj2Fn()
               ); ;
           Console.WriteLine("Main End");
           Console.ReadLine();
       }
       public static void obj1Fn()
       {
           SingleTon obj1 = SingleTon.getInstance;
           obj1.printText("obj1");
       }
       public static void obj2Fn()
       {
           SingleTon obj2 = SingleTon.getInstance;
           obj2.printText("obj2");
       }
   }
   class SingleTon
   {
       private static int objectCounter = 0;
       private static SingleTon instance;
       private SingleTon()
       {
           objectCounter++;
           Console.WriteLine("objectCounter : " + objectCounter.ToString());
       }
       public static SingleTon getInstance
       {
           get
           {
               if (instance == null)
                   instance = new SingleTon();
               return instance;
           }
       }
       public void printText(string strData)
       {
           Console.WriteLine(strData);
       }
   }
Output
   objectCounter : 1
   objectCounter : 2
   obj1
   obj2
   Main End

Problem 2

Example
   class Program
   {
       static void Main(string[] args)
       {
           SingleTon.SingleTonChild obj1 = new SingleTon.SingleTonChild();
           obj1.printText("obj1");
           SingleTon.SingleTonChild obj2 = new SingleTon.SingleTonChild();
           obj2.printText("obj2");
           Console.WriteLine("Main End");
           Console.ReadLine();
       }
   }
   class SingleTon
   {
       public class SingleTonChild: SingleTon
       {
       }
       private static int objectCounter = 0;
       private static SingleTon instance;
       private static readonly object lockObj = new object();
       private SingleTon()
       {
           objectCounter++;
           Console.WriteLine("objectCounter : " + objectCounter.ToString());
       }
       public static SingleTon getInstance
       {
           get
           {
               if (instance == null)
               {
                   lock (lockObj)
                   {
                       if (instance == null)
                           instance = new SingleTon();
                   }
               }
               return instance;
           }
       }
       public void printText(string strData)
       {
           Console.WriteLine(strData);
       }
   }
Output
   objectCounter : 1
   obj1
   objectCounter : 2
   obj2
   Main End

Second version - simple thread-safety and sealed

   class Program
   {
       static void Main(string[] args)
       {
           System.Threading.Tasks.Parallel.Invoke(
               () => obj1Fn(),
               () => obj2Fn()
               ); ;
           Console.WriteLine("Main End");
           Console.ReadLine();
       }
       public static void obj1Fn()
       {
           SingleTon obj1 = SingleTon.getInstance;
           obj1.printText("obj1");
       }
       public static void obj2Fn()
       {
           SingleTon obj2 = SingleTon.getInstance;
           obj2.printText("obj2");
       }
   }
   sealed class SingleTon
   {
       private static int objectCounter = 0;
       private static SingleTon instance;
       private static readonly object lockObj = new object();
       private SingleTon()
       {
           objectCounter++;
           Console.WriteLine("objectCounter : " + objectCounter.ToString());
       }
       public static SingleTon getInstance
       {
           get
           {
               lock (lockObj)
               {
                   if (instance == null)
                       instance = new SingleTon();
               }
               return instance;
           }
       }
       public void printText(string strData)
       {
           Console.WriteLine(strData);
       }
   }

Output

   objectCounter : 1
   obj1
   obj2
   Main End

Third version - attempted thread-safety using double-check locking

   class Program
   {
       static void Main(string[] args)
       {
           System.Threading.Tasks.Parallel.Invoke(
               () => obj1Fn(),
               () => obj2Fn()
               ); ;
           Console.WriteLine("Main End");
           Console.ReadLine();
       }
       public static void obj1Fn()
       {
           SingleTon obj1 = SingleTon.getInstance;
           obj1.printText("obj1");
       }
       public static void obj2Fn()
       {
           SingleTon obj2 = SingleTon.getInstance;
           obj2.printText("obj2");
       }
   }
   sealed class SingleTon
   {
       private static int objectCounter = 0;
       private static SingleTon instance;
       private static readonly object lockObj = new object();
       private SingleTon()
       {
           objectCounter++;
           Console.WriteLine("objectCounter : " + objectCounter.ToString());
       }
       public static SingleTon getInstance
       {
           get
           {
               if (instance == null)
               {
                   lock (lockObj)
                   {
                       if (instance == null)
                           instance = new SingleTon();
                   }
               }
               return instance;
           }
       }
       public void printText(string strData)
       {
           Console.WriteLine(strData);
       }
   }

Output

   objectCounter : 1
   obj1
   obj2
   Main End

Singleton class vs. Static class