Card image cap

Exploring Design Patterns - Understanding The Singleton

A Singleton pattern is one of the twenty three design patterns compiled to solve specific design problems which occur recursively across the software development. The Singleton pattern is a creational pattern which deals with how to create a class instance so that it is restricted to be created only once in its entire lifecycle and only one instance is to be used across the system in the entire flow. Simply put, it restricts the instantiation of a class to only one instance. This is one of the most simplest patterns which needs to be used carefully and only in required scenarios. When used unnecessarily, singleton patterns can create additional problems and can complicate the system flow which we call as an "anti-pattern" behavior.

A Singleton class can be simply created in three steps:

  1. Hide the constructor of the class by marking it private.

  2. Define a private static variable of the class to be made singleton and store an instance of the class to return.

  3. Define a public static method which can return the persisted instance of the class (stored in the private static field) when invoked.

For example in C# we can mark a class which offers some functionality as a singleton based on our requirement by following the above steps.

Let's take the example of a Http utility class that offers a http get functionality for a given URL and headers.


namespace netcore3app.Providers
{
    public class Http
    {
        private HttpClient client = new HttpClient();

        public async Task<HttpResponseMessage> GetHttp(string url, Dictionary<string, string> headers)
        {

            var request = new HttpRequestMessage(HttpMethod.Get, url);

           foreach (var header in headers)
           {
            request.Headers.TryAddWithoutValidation(header.Key, header.Value);
            }

            return await client.SendAsync(request);
        }
    }
}

Now we don't desire the utility class to be instantiated every time we require (since it's costly to have multiple instances of HttpClient be created). We instead look to convert this class into a Singleton so that only one instance of the utility and thereby HttpClient be rotated across the system for all Http operations.

For that we mark the class as sealed (to prevent any inheritance by extension) and have a private static field that holds an instance of itself.


namespace netcore3app.Providers.Singletons
{
    // a singleton class
    public sealed class Http
    {
        private static HttpClient client = new HttpClient();

        // the single instance
        // which is always returned
        private static Http instance = null;

        // some functionality
        public async Task<HttpResponseMessage> GetHttp(string url, Dictionary<string, string> headers)
        {
            var request = new HttpRequestMessage(HttpMethod.Get, url);
 
            foreach (var header in headers)
            {
             request.Headers.TryAddWithoutValidation(header.Key, header.Value);
            }

            return await client.SendAsync(request);
        }
 
       // a private constructor
        private Http()
        {
        }

        // the method that returns an instance
        public static Http GetInstance()
        {
            if (instance == null)
            {
                instance = new Http();
            }
            return instance;
        }
    }
}

We then have the constructor marked private to restrict instantiation and add a new method GetInstance() that returns the instance of itself when invoked. The method further delays instantiation of the class till the point of invocation and thereby creating a Lazy Initialization effect.

Another implementation can be having a static class which manages the Http utility object for us.


namespace netcore3app.Providers.Singletons
{
    // a static class is singleton by nature
    public static class HttpSingleton
    {
        // a private field to hold the instance of the type
        private static readonly Http instance = new Http();

        // a public property that returns the created instance
        public static Http Instance => instance;
    }
}

This way we can create Singletons which can help reduce the number of instances created and contribute to the overall system's performance (considerably). However, with the advent of container frameworks such as Autofac or Ninject, marking a class as a Singleton has become easy and simplified, with the frameworks doing the heavy lifting for us. And in newer ASP framework aka the ASP.NET Core brings this feature built-in with its own container for instantiations, and so these approaches are not so required when using these frameworks.

Other Creational Patterns:

The Abstract Factory Pattern

The Factory Pattern

The Prototype Pattern

The Singleton Pattern

Published one month ago

Sponsored Links
We use cookies to improve user experience. Learn More