Design Patterns - Singleton

·

3 min read

Singleton classes can only be initiated once.

The Singleton pattern ensures the class has only one instance and provides global point of access to it.

Singleton is an anti-pattern and should be avoided in javascript.

Note- In other programming languages like we cannot create objects directly. However in JS we can create objects directly and using class implementation is an overkill.

Advantages:

Saves memory, since only one instance is created throughout the lifecycle of the application.

Disadvantages:

It is considered anti-pattern Hides Dependency details: When we import a singleton class its not evident from that it would be implementing singleton design pattern and we might accidentally update the global state

Global behavior: A Singleton instance should be able to get referenced throughout the entire app. Global variables essentially show the same behavior: since global variables are available on the global scope, we can access those variables throughout the application. index.js Having global variables is generally considered as a bad design decision. Global scope pollution can end up in accidentally overwriting the value of a global variable, which can lead to a lot of unexpected behavior.

Java Implementation:

To make a class singleton we have to follow below steps:

  1. create a class which is public

  2. create a reference to the instance of the class which is private and static

  3. create a private constructor

  4. expose a public and static method to get instance of the class

Method-1

Eager Initialization - As soon as we load the application, because of static keyword methods and variables will be preloaded , even though nobody is using it.

This is its disadvantage. DB connection activity can be expensive.

public class DbConnection{

  // eager initialization
  private static DbConnection staticDbInstance = new DbConnection();

  private DbConnection(){}

  public static DbConnection getInstance(){
    return staticDbInstance;
  }

}

Method-2

Lazy Initialization - Check whether object is initialized or not

Disadvantage - What if two threads try to access ot at the same time and object is not initialized yet ?

Both will find staticDbInstance is null and two objects will be created

public class DbConnection{

  // late initialization
  private static DbConnection staticDbInstance;

  private DbConnection(){}

  public static DbConnection getInstance(){
    if(staticDbInstance == null){
        staticDbInstance = new DbConnection();
    }
    return staticDbInstance
  }

}

Method-3

use synchronized keyword to method

by adding this keyword we force every thread to wait for its turn

Imp

Disadvatage - Very slow

Suppose we calling getInstance method at 100 different places parallely, 100th place will have to wait until all 99 places have finished executing.

After executing at place 1 synchronized on method is an overhead

public class DbConnection{

  // late initialization
  private static DbConnection staticDbInstance;

  private DbConnection(){}

  public static synchronized DbConnection getInstance(){
    if(staticDbInstance == null){
        staticDbInstance = new DbConnection();
    }
    return staticDbInstance
  }

}

Method-4

Double-Locking

make the instance reference volatile. volatile keyword ensures that multiple thread handles the unique instance variable correctly when it is being initialized to single instance

when we use volatile keyword any read / write happens from memory and not from cache

Still this is slow

public class DbConnection{

  // late initialization
  private static volatile DbConnection staticDbInstance;

  private DbConnection(){}

  public static synchronized DbConnection getInstance(){
    // Double check
    if(staticDbInstance == null){
        synchronized(DbConnection.class){
            if(staticDbInstance == null){
                staticDbInstance = new DbConnection();
            }
        }
    }
    return staticDbInstance
  }

}

Method-5

Bill Pugh Solution

uses eager initialization. create a private nested class and use eager initialzation

nested class do not get loaded at the time of start of application

public class DbConnection{

  private static  class DbConnectionHelper(){
    private static final DbConnection INSTANCE_OBJ= new DbConnection();
  }

  public static DbConnection getInstance(){
      return DbConnectionHelper.INSTANCE_OBJ;
  }

}

Method-6

use enum

In enum by default all constructor are private As per JVM enums are singleton by design

enum DbConnection{
    INSTANCE;
}