Difference between revisions of "Singleton Design Pattern"

From JholJhapata
 
(2 intermediate revisions by the same user not shown)
Line 2: Line 2:
 
[[File:Singleton.png|thumb|Singleton]]
 
[[File:Singleton.png|thumb|Singleton]]
 
== Problem ==
 
== Problem ==
Application needs one, and only one, instance of an object.
+
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 ====
 
==== Example ====
 
Let’s take a look at an example, which is creating multiple objects.
 
Let’s take a look at an example, which is creating multiple objects.
Line 11: Line 11:
 
         {
 
         {
 
             SingleTon obj1 = new SingleTon();
 
             SingleTon obj1 = new SingleTon();
 +
            obj1.printText("obj1");
 
             SingleTon obj2 = new SingleTon();
 
             SingleTon obj2 = new SingleTon();
 +
            obj2.printText("obj2");
 
             Console.WriteLine("Main End");
 
             Console.WriteLine("Main End");
 
             Console.ReadLine();
 
             Console.ReadLine();
Line 31: Line 33:
 
==== Output ====
 
==== Output ====
 
     objectCounter : 1
 
     objectCounter : 1
 +
    obj1
 
     objectCounter : 2
 
     objectCounter : 2
 +
    obj2
 
     Main End
 
     Main End
 +
 +
We created 2 object for printing text log.
 
== Solution ==
 
== Solution ==
 
The common characteristics of a Singleton Pattern:
 
The common characteristics of a Singleton Pattern:
Line 40: Line 46:
 
* A public static means of getting the reference to the single created instance, creating one if necessary.
 
* A public static means of getting the reference to the single created instance, creating one if necessary.
 
=== First version - not thread-safe ===
 
=== 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 ====
 
==== Output ====
=== Second version - simple thread-safety ===
+
    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 ====
 
==== Output ====
 +
    objectCounter : 1
 +
    obj1
 +
    obj2
 +
    Main End
 
=== Third version - attempted thread-safety using double-check locking ===
 
=== 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 ====
 
==== Output ====
 +
    objectCounter : 1
 +
    obj1
 +
    obj2
 +
    Main End
 
== Singleton class vs. Static class ==
 
== Singleton class vs. Static class ==

Latest revision as of 18:29, 10 December 2019

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