Singleton pattern

In layman terms: A single entity for all accessors. Analogous to sharing a single refrigerator among all the family members

This pattern involves a single class which is responsible to create an object while making sure that only single object gets created. The Singleton pattern disables all other means of creating objects of a class except for the special creation method. This method either creates a new object or returns an existing one if it has already been created. All implementations of the Singleton have these two steps in common:

  • Make the default constructor private, to prevent other objects from using the new operator with the Singleton class.
  • Create a static creation method that acts as a constructor. Under the hood, this method calls the private constructor to create an object and saves it in a static field. All following calls to this method return the cached object.

Typical use cases: DB access objects, registries are a good places to use singletons.

An example below

In the below example, there is only one instance of BankAccount in memory. All these different clients actually use the same instance for updating it and fetching their info. You can try creating any number of instances for the class but it'll only persist a single instance.

export class BankAccount {
  // Class object instance
  // This is static & private to class
  static #bankAccountInstance;

  // A static method used to create instances
  static create() {
    if (!BankAccount.#bankAccountInstance) {
      BankAccount.#bankAccountInstance = new BankAccount();
    }
    return BankAccount.#bankAccountInstance;
  }

  constructor() {
    if (BankAccount.#bankAccountInstance) {
      throw new Error(
        'Cannot create instances. Use static "create" method for creating instances',
      );
    }
    console.log('Creating a new instance of bank account...');
  }
}
Balance: 0
Google pay
PayTM
PhonePe
My Bank ATM
Other bank ATM
Bank branch
You can play around with this example in your console. You can access the BankAccount through global BankAccount
  1. Try creating new instance new BankAccount() & see that it throws error.
  2. Access instance through BankAccount.create() method & invoke deposit100() and withdraw100() methods & you would see that the value on your screen also increases
  3. You can invoke create any number of times & they'll all be pointing to be same instance

References:

  1. Singleton pattern
    https://refactoring.guru/design-patterns/singleton
  2. Blog discussing about pros & cons of singleton pattern
    https://www.digitalocean.com/community/tutorial_series/javascript-design-patterns
  3. Digital Ocean list of patterns
    http://blog.rcard.in/design/programming/2015/07/03/the-good-the-bad-and-the-singleton.html