Singleton Design Pattern

The Singleton design pattern is a creational design pattern that restricts the instantiation of a class to one object, ensuring that only one instance of the class can be created and used throughout the entire application. 

The Singleton pattern is widely used in software development to solve many problems, including managing shared resources, caching, logging, and configuration settings. In this blog, we will discuss the Singleton design pattern, its characteristics, benefits, and drawbacks, and when to use it.


Benefits of the Singleton Design Pattern

The Singleton design pattern offers several benefits, including

Efficient Resource Utilization 

The Singleton pattern allows for efficient resource utilization by ensuring that only one instance of the class is created and used throughout the application.


Global Access 

The Singleton object can be accessed from anywhere in the application, providing a global point of access.


Easy to Implement 

The Singleton pattern is easy to implement and is widely used in software development.


Improved Performance 

The Singleton pattern can improve performance by reducing the number of objects created and used in the application.


Drawbacks of the Singleton Design Pattern

While the Singleton pattern offers many benefits, it also has some drawbacks, including 

Tight Coupling

Singleton pattern often leads to tight coupling between objects, which can make it difficult to modify or extend the code later. This can make the code less flexible and more difficult to maintain.


Global State 

Singleton pattern creates a global state, which can be problematic in large, complex systems. A global state can lead to unexpected interactions between objects and can make it difficult to reason about the behavior of the system.


Difficulty in Testing 

Singleton pattern can make it difficult to test and mock objects, as it creates a static dependency that cannot be easily replaced. This can make it difficult to write effective unit tests and can lead to brittle code.


Hidden Dependencies 

The Singleton pattern can hide dependencies, making it difficult to know which objects are using the Singleton object and make it difficult to replace them with different objects in the future. This becomes a problem when the dependencies on this object increases.


Performance Issue

Singleton pattern can negatively impact performance in some cases, as it can introduce additional overhead due to the synchronization mechanisms required to ensure thread safety.


When to use the Singleton Design Pattern

The Singleton pattern is best used in situations where you need to ensure that there is only one instance of a class throughout the application. Some common use cases are

Database Connection in Some Scenarios

A database connection class that connects to a database and manages connections could be implemented as a singleton. This ensures that all parts of the application are using the same database connection and reduces the overhead of creating multiple connections.


Application Data Caching

A caching class that stores frequently accessed data could be implemented as a singleton. This ensures that all parts of the application are using the same cache and reduces the need to create multiple instances of the cache class.


Accessing Application Configuration Settings 

A configuration class that stores application-wide settings such as database credentials, API keys, and other settings could be implemented as a singleton. This ensures that all parts of the application have access to the same configuration settings.



Logging

A logging class that is used throughout the application could be implemented as a singleton. This ensures that all log messages are written to the same log file or database.


Thread pool 

A thread pool class that manages a pool of threads could be implemented as a singleton. This ensures that all parts of the application are using the same thread pool and reduces the overhead of creating multiple thread pools.


State management 

A state management class that manages the state of the application could be implemented as a singleton. This ensures that all parts of the application are using the same state and reduces the potential for conflicts between different parts of the application.


Implementation 

There are multiple ways you can implement Singleton design pattern such as 

1. You can implement the Singleton pattern by making the class constructor private and providing a static method that returns the instance of the class. Here's an example: of the singleton pattern includes two steps 

  1. public class Singleton
  2. {
  3.     private static Singleton instance;

  4.      private Singleton()
  5.     {
  6.         
  7.     }

  8.     public static Singleton getInstance()
  9.     {
  10.        if(instance == null)
  11.        {
  12.           instance = new Singleton();
  13.        }
  14.        return instance;
  15.     }
  16. }


In this implementation, the constructor is private, so no other class can create an instance of the Singleton class. The static getInstance() method returns the instance of the Singleton class, creating it if it doesn't exist yet. The instance variable is also static, so it is shared among all instances of the class.

Note that this implementation is not thread-safe, so if multiple threads try to access the getInstance() method simultaneously, they may create multiple instances of the Singleton class. To make the Singleton pattern thread-safe, you can use the double-checked locking technique, Eager Initialization or Synchronized as explained later in this blog.


2. Most of the dependency injection frameworks supports the Singleton pattern as a scope for managing object lifecycles. In these frameworks, you can register class with singleton scope to create a Singleton object. However, note that these frameworks may use different techniques to manage object instantiation and may not follow the traditional Singleton pattern implementation.



Singleton vs Static Class

Some key differences between Singleton and Static class are

Singleton

Static

A Singleton class is a class that allows only one instance of itself to be created and provides a global point of access to that instance. The Singleton pattern is often used when a single instance of a class needs to coordinate actions across an entire system

A static class is a class that cannot be instantiated and provides only static members, such as static methods or static properties. A static class is often used when a class has a set of utility methods that do not require any state to be maintained.

An instance is typically created lazily or eagerly

There is no instance to create.

A Singleton class can be inherited and able to maintain its state. 

Static class can't be inherited and does not have its own state.

A Singleton class provides a single point of access to an instance

A static class provides access to static members without needing to create an instance.


How do you make a Singleton class thread-safe

To make a Singleton class thread safe, you need to ensure that only one instance of the class is created even when multiple threads attempt to access it concurrently. 

Here are three common approaches for achieving thread safety in Singleton class creation:

1. Eager Initialization

In this approach, the Singleton instance is created at the time of class loading, before any thread has a chance to access the class. This approach ensures thread safety by guaranteeing that only one instance of the Singleton class is ever created.


2. Synchronized method

In this approach, the getInstance() method, which returns the Singleton instance, is marked as synchronized. This ensures that only one thread can enter the method at a time, preventing multiple instances from being created concurrently. 

  1. public class Singleton
  2. {
  3.     private static Singleton instance;

  4.      private Singleton()
  5.     {
  6.         
  7.     }

  8.     public static synchronized Singleton getInstance()
  9.     {
  10.        if(instance == null)
  11.        {
  12.           instance = new Singleton();
  13.        }
  14.        return instance;
  15.     }
  16. }

While this approach ensures thread safety, it can be slow, as the synchronized keyword causes contention between threads.


3. Double-checked Locking: 

In this approach, the getInstance() method checks whether an instance of the Singleton class has already been created, and if not, it synchronizes the creation of the instance. This approach avoids the overhead of synchronization in the common case where the instance has already been created.

  1. public class Singleton
  2. {
  3.     private static volatile Singleton instance;

  4.      private Singleton()
  5.     {
  6.         
  7.     }

  8.     public static Singleton getInstance()
  9.     {
  10.        if(instance == null)
  11.        {
  12.           synchronized (Singleton.class)
  13.           {           
  14.            if(instance == null)
  15.            {
  16.              instance = new Singleton();
  17.            }
  18.           }
  19.        }
  20.        return instance;
  21.     }
  22. }

The use of the volatile keyword ensures that the instance variable is visible to all threads, while the double-checked locking ensures that only one instance is created.



Comments

Popular posts from this blog

Design Patterns

Abstract Factory Design Pattern

Azure Container Registry (ACR)

Factory Design Pattern

What is Azure DevOps?