Design Patterns: Singleton Pattern

Get a solid grasp on the Singleton pattern

·

3 min read

We previously defined software design patterns and took a look at some well-known design patterns. Let's take a deeper look at the Singleton pattern here.

The Singleton pattern is a creational design pattern that restricts the instantiation of a class to one object and provides a global point of access to that instance. This pattern is suitable for situations where there should be only one instance of a class in a system, such as managing access to shared resources or configurations.

One common example of the Singleton pattern is a logging system in a software application. A logging system is typically used to record important events and information during the execution of an application, and it is important to ensure that only one instance of the logging system exists in the application. By using the Singleton pattern, the logging system can be designed to be instantiated only once and then made available globally throughout the application. This helps to prevent any conflicts or inconsistencies in the logged information that could arise from multiple instances of the logging system.

Perhaps a more common example of the Singleton pattern is a database connection pool. A database connection pool is a collection of database connections that are created and maintained in memory for reuse, instead of opening and closing connections for each request. The Singleton pattern can be used to ensure that there is only one instance of the connection pool in the application, which can then be used to manage all database connections in the system. This can help to reduce the overhead of creating and destroying connections and improve the overall performance of the system.

Generally, the Singleton pattern should be used in situations where there is a need for only one instance of a class in the system, and where that instance needs to be accessed globally. However, it is important to use this pattern judiciously, as overuse of the Singleton pattern can lead to tight coupling and make the code more difficult to maintain and test.

Here is a practical example of the Singleton pattern being implemented.

'use strict'
const School = (function() {
  let instance;

  function createInstance() {
    // Private variables
    const teachers = [];

    function addTeacher(name, subject) {
      teachers.push({ name, subject });
    }

    function getTeachers() {
      return teachers;
    }

    return {
      addTeacher,
      getTeachers
    };
  }

  return {
    getInstance: function() {
      if (!instance) {
        instance = createInstance();
      }
      return instance;
    }
  };
})();

Object.freeze(School)

// Usage
const school1 = School.getInstance();
school1.addTeacher("John", "Math");
school1.addTeacher("Mary", "English");

const school2 = School.getInstance();
console.log(school2.getTeachers());

In this example, the Singleton pattern is implemented using an immediately invoked function expression (IIFE), which returns an object with a getInstance method. The getInstance method checks if the instance of the class exists and creates it if it does not. This ensures that only one instance of the class exists in the system.

The private variables of the School class are teachers, which is an array of teacher objects, and the methods are addTeacher and getTeachers, which are used to add and retrieve teachers from the teachers array.

The Singleton pattern is used to create a single instance of the School class and then to add teachers to it. The school1 object is created by calling the getInstance method of the School class and then the addTeacher method is called on the school1 object to add two teachers. The school2 object is then created by calling the getInstance method of the School class again, and the getTeachers method is called on the school2 object to retrieve the teachers added to school1.

The Singleton pattern is particularly useful in situations where shared resources or configurations need to be managed. However, it should be used judiciously to avoid tight coupling and make the code difficult to maintain and test.

Next up, we will take a look at the Observer pattern. Follow for more.

Did you find this article valuable?

Support Clint by becoming a sponsor. Any amount is appreciated!