Singleton pattern in Node.js
Design patterns are incredibly useful and one of the best programming practices followed by software developers.
They provide solutions to those problems that are recurrent during software development. They are also known as GoF (gang of four) Design Patterns, and there are three types of software design patterns: Creational, behavioral, and structural.
We'll discuss one of the creational patterns called the singleton pattern.
Singleton pattern
The singleton pattern, as the name suggests, represents a single instance of a class.
To enforce this single instance rule, the class uses a private constructor. This prevents external classes from creating new instances of the class directly. The purpose of the Singleton pattern is to enforce the presence of only one instance of a class.
That single instance is responsible for coordinating actions and managing resources while providing a centralized point of control across all the components of an application.
Use cases
There are many use cases where we need to use a single instance with centralized access. There are a few use cases for using a single instance:
For database connections
For configuration management
For logging management
For sharing stateful information
For optimizing resource usage
For implementing thread pools
For managing the cache
Code explaination
Consider a scenario where we implement the singleton pattern using the exportlogger.js, that ensures there is a single instance of the logger throughout the module and a test file main.js to see how we can use the logger module.
Note: We will use the version 14 or later of Node.js.
// Importing the public method of Logger moduleimport { getInstance } from './logger.js'// Getting the singleton instanceconst instance1 = getInstance()const instance2 = getInstance()// Checking if both instances refer to the same object or notif (instance1 === instance2)console.log('Both instances refer to the same object')// Using the Logger to log messagesinstance1.log('I am instance 1')instance2.log('I am instance 2')// Logging entries of both instancesconsole.log(instance1.logs)console.log(instance2.logs)
Just a heads-up: logger.js and main.js are both in the same Code Widget. You can find them on the left side of the widget.
Explanation
logger.js:Line 2: We declare a variable
instanceand initialize it tonullto hold a single instance of the class.Lines 5–14: The
Loggerclass has a constructor that initializes thelogsinstance variable as an empty array. It also includes alog()method that adds a message to thelogsarray and logs it to the console.Lines 17–23: The
getInstance()method provides access to a single instance of the class. It checks theinstancevariable and, if it isnull, creates a newLoggerinstance and assigns it toinstance. It then returns this instance, ensuring that all future calls togetInstance()return the same object.Line 26: This line exports the
getInstancemethod using theexportkeyword.
Now let's look at the main.js file explanation below:
main.js:Line 2: We import the
getInstancefunction from thelogger.jsmodule using theimportkeyword. ThegetInstancefunction is the public method that provides access to the singleton instance of theLoggerclass.Lines 5-6: We call the
getInstance()method twice, creating two instances,instance1andinstance2of theLoggerclass.Lines 9-10: We check if
instance1andinstance2refer to the same object. Since thegetInstancefunction ensures that there is only one instance, bothinstance1andinstance2will refer to the same object. So, if this is true, which is expected due to the Singleton pattern, it logs the message to the console.Lines 13-14: We call the
logmethod for both instancesinstance1andinstance2, to log messages.Lines 17-18: We print the
logsarray of both instancesinstance1andinstance2to the console. Since both instances share the same instance of theLoggerclass, they also share the samelogsarray. The console output will show the log entries of both instances.
Conclusion
The singleton pattern is useful when we need a single access point to a resource or service. It provides a simple and centralized solution. However, since it offers global access, it should be used with care. Overuse can affect the modularity and testability of the application.
Free Resources