Singleton Pattern   «Prev  Next»
Lesson 9 Singleton: known uses
Objective Explore Real World Examples of the Singleton Design Patterns.

Known Uses of the Singleton Design Pattern


The Singleton Design Pattern is frequently employed in software development, and you can find a myriad of real-world examples. One common use case is the logging mechanism. Imagine you have an application that is writing to a log file to keep track of errors, system events, or debug information. You certainly don't want multiple instances of a logger object writing to the same file simultaneously, as this could lead to file corruption or conflicting entries. Instead, a Singleton logger ensures that one and only one instance is responsible for writing to the log file, thus preserving the integrity and consistency of the logged data.
Another example is a configuration object. Often, applications require a set of configuration parameters to be accessible application-wide. Instead of reading a configuration file every time these parameters are needed, a Singleton can be used to read the file once and then provide the configuration parameters globally to the entire application. Now, let's look at an example of a Singleton in Node.js. We'll implement a simple configuration manager.
class ConfigManager {
    constructor() {
        // Check if an instance already exists
        if (ConfigManager.instance) {
            return ConfigManager.instance;
        }

        // Set up your config from a file, process.env, or any other source
        this.config = {
            key: 'your-value'
            // add more configuration parameters as needed
        };

        // Make sure to save the reference of the instance
        ConfigManager.instance = this;

        // Freeze the instance to prevent modifications
        Object.freeze(ConfigManager.instance);
    }

    // Method to get a config parameter
    getConfig(key) {
        return this.config[key];
    }

    // Method to set a config parameter
    setConfig(key, value) {
        this.config[key] = value;
    }
}

module.exports = new ConfigManager();

In this code, we create a ConfigManager class that provides a global point of access to configuration parameters. The constructor checks if an instance of ConfigManager already exists. If it does, it returns that instance. If not, it sets up the configuration and saves the instance. We export a new instance of the ConfigManager class. Because Node.js caches the result of the first require() call for a given file, any subsequent require() calls for the same file will return the same instance. This is essentially how Singleton behavior is achieved in Node.js.
Remember to be cautious with Singletons as their global nature can introduce unwanted coupling in your codebase and make testing more difficult. Always evaluate if the Singleton pattern is the most suitable solution to your problem.


Applicability of the Singleton Design Pattern

Use the Singleton pattern when:
  1. There must be exactly one instance of a class, and it must be accessible to clients from a well-known access point
  2. When the sole instance should be extensible by subclassing, and clients should be able to use an extended instance without modifying their code.

The Singleton pattern restricts a class so that only one instance can be created. This can be accomplished by
  1. making its constructor private or protected and
  2. providing an instance() member that returns a pointer to a new instance if one does not already exist but returns a pointer to that instance if it does.

Having an instance of the class in a global variable seems like an easy way to maintain the single instance. All client objects can access this instance in a consistent manner through this global variable. But this does not prevent clients from creating other instances of the class. For this approach to be successful, all of the client objects have to be responsible for controlling the number of instances of the class. This widely distributed responsibility is not desirable because a client should be free from any class creation process details. The responsibility for making sure that there is only one instance of the class should belong to the class itself, leaving client objects free from having to handle these details. A class that maintains its single instance nature by itself is referred to as a Singleton class.


One known use of the Singleton pattern is found in the hidden parts of the Java class library.
The audio device example I used earlier is not a mere fantasy. The sun.audio.AudioDevice class actually exists, and is used in more or less the way I described.
The Gang of Four lists several other known uses of Singleton patterns, including
  1. Changeset current in SmallTalk-80, and the
  2. Session and WidgetKit classes in the InterViews user interface toolkit.
Once you have learned to recognize a design pattern, you will begin to see it in many places. The Java class library in particular is riddled with examples of classic design patterns. It is somewhat obvious that at least some of the programmers writing code for the java packages are pattern aficionados.

NodeJS Design Patterns

Singleton used to control Access

One of the ways you use the Singleton pattern is to cover an instance where there must be a single "broker" controlling access to a resource. Singletons perform the task of loggers well because they broker access to a log file, which can only be written to exclusively. For a task such as logging, a Singleton provides a way of abstracting away the writing task to a log file.
Also think of a situation where you have an application with many windows, threads, and processess and need a single point of communication. The Singleton could be used to control tasks to launch your application. The singleton could be used to serialize the jobs and display their status to any other part of the program which required the information. In this type of scenario, you can think of a Singleton as functioning as a "server" class running inside your application.

SEMrush Software