Design Patterns - Singleton

18 March 2022 at 10:00 by ParTech Media - Post a comment

In our previous blog of the design pattern series, we discussed the Factory Method design pattern which falls under the category of creational design patterns. In this post, we will explore the Singleton design pattern which also falls under the same category. Let’s begin the post right away.

Table of contents

  1. Singleton Design Pattern
  2. How to implement Singleton Design Pattern?
  3. Scenarios
  4. Final Thoughts

Singleton Design Pattern

Singleton design pattern in C# is one of the most common and widely used design patterns across all the categories. The primary role of the singleton pattern is to provide only one instance of a class throughout the application. This may sound like serving the purpose of a static class that is available in C# by default, but static classes do not support the feature of inheritance and cannot be instantiated.

How to implement Singleton Design Pattern?

A typical singleton pattern follows the below characteristics -

  • Private parameterless constructor
  • Sealed class
  • Static variable to hold the created instance

A private constructor is used to ensure that a new instance of the class is not created. Making it sealed ensures that it cannot be inherited. To create or get the instance, a static method is used so that it can be accessed directly with just the class name. Let's understand the template of the singleton design pattern now.

using System;

namespace PARTECH_Singleton
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Singleton instance1 = Singleton.Instance;
            Singleton instance2 = Singleton.Instance;

            if (instance1 == instance2)
            {
                Console.WriteLine("Instances are same.");
            }

            Console.ReadLine();
        }
    }

    public sealed class Singleton
    {
        private Singleton()
        {

        }

        private static Singleton instance;
        public static Singleton Instance 
        { 
            get 
            {
                if (instance == null)
                    instance = new Singleton();

                return instance; 
            } 
        }

    }
}

The above code has a main method and a class named Singleton. The Singleton class is of type sealed and has a private constructor. It has a private variable to hold the instance and a public variable getter to assign the value to the private variable.

In the main method, the instance of the Singleton is created and assigned to a variable. And in the next line, the same line of code is repeated and assigned to a different variable. Next, both the variables are compared to check if they are the same (the same message is printed).

This is a simple Singleton design pattern template that can be used in applications where only one thread performs all the operations. Imagine we have scenarios where multiple threads are using the application to process. In such scenarios (due to timing issues), there are chances that two different instances get created as the thread code executes in parallel. Let's now see how to implement a thread-safe singleton pattern.


    public sealed class SingletonWithLock
    {
        private SingletonWithLock()
        {

        }
        private static readonly object lockObject = new object ();

        private static SingletonWithLock instance;
        public static SingletonWithLock Instance
        {
            get
            {
                lock (lockObject)
                {
                    if (instance == null)
                    {
                        instance = new SingletonWithLock();
                    }
                }
                return instance;

            }
        }

    }

In the above code, the lockObject is implemented and allows only one instance to access at a time. The class names are modified as required in the code.

In the lock code, even if the instance is already created, a lock will be applied, which is a performance-impacting activity. To avoid this, double-check lock safety singleton patterns can be implemented as below.


        public static SingletonWithLock Instance
        {
            get
            {
		if (instance == null)
		{
                lock (lockObject)
                {
                    if (instance == null)
                    {
                        instance = new SingletonWithLock();
                    }
                }
	}
                return instance;

            }
        }

In the above code, the instance state is first checked, based on which the lock is implemented. In case the instance is already created, then the lock will not be implemented. This avoids performance issues. So far we have seen how to create instances of a singleton class only when the method is called, in other words without lazy instantiation. Let’s now see another case.


 public sealed class SingletonWithStatic
    {
        private static readonly SingletonWithStatic instance; 
        
        private SingletonWithStatic()
        {

        }

        static SingletonWithStatic()
        {
            instance = new SingletonWithStatic();
        }

        public static SingletonWithStatic getInstance()
        {
            return instance;
        }
    }

In the above code, instead of placing the object instantiation logic inside the getInstance public property, a static constructor is created. And inside the static constructor, the object is instantiated by default. As the static constructors will be executed only when the application starts, the object will be created only during then, and whenever the getInstance is called and the already created object’s instance is returned. It also makes the code look simple without the lock mechanism and double-checking of the instance.

Scenarios

Singleton can be implemented in scenarios where the content of the class need not be altered through the execution of the code.

Say, for example, all the applications will have a class to maintain the configuration which can be used throughout the application. Such configuration classes can be implemented in the Singleton Design pattern way. The same applies to logger classes.

Inversion of Control (IoC) is one of the core SOLID principles, under which the hood dependency injection is present. The concept is to provide or inject the dependency instead of the calling class passing it.

Dependency injection is available by default in C#. Developers can make use of this and define the scope of the injecting parameter, where Singleton is one of the scopes that are pre-loaded. Developers, if they opt for DI, can make use of the in-built singleton pattern application for the custom classes, rather than creating a logic for implementing it.

Final Thoughts

And that’s what a Singleton creational design pattern is all about. We have also seen how it can be implemented in a real-world scenario in this post. Stay tuned for the next blog on Design Patterns.

Latest