Singleton Pattern and ES6 Modules
Singleton Pattern
Chapter 1: Introduction
A singleton is a single instance of a class that can be shared throughout the entire application.
With regular classes, a new instance is created each time the class is imported and instantiated.
Singletons ensure that only one instance is used across the application.
Example:
file1imports a singleton counter, increments it, and the increment is reflected in other files because they all share the same instance.In ES6, there are multiple ways to create singletons; one way is using a class.
Chapter 2: The New Instance
When instantiating a singleton class:
Ensure an instance doesn't already exist.
If an instance exists, throw an error to prevent creating another one.
The instance variable is set to the new instance when we instantiate it.
Singletons should be non-modifiable.
Use
Object.freeze()in JavaScript to prevent adding or changing properties of the singleton object.Instantiate the class as a singleton in the file before exporting it, so files import the instance, not the class itself.
Chapter 3: Import The Instance
Files import the instance and not the class to prevent instantiation of the already instantiated instance.
Freeze the instance to ensure it's not modifiable.
In ES6, objects can be used instead of classes for singletons.
Example: Create a counter object with
getCount,increment, anddecrementmethods.Freeze the object and export it for use in other files.
Trade-offs of singletons:
Good for memory management as only one instance is created.
Cons:
ES15 modules are singletons by default, reducing the need to explicitly create singletons.
Dependency hiding: a singleton might import another module, leading to unintended modifications.
Difficult to test: global changes can cause the entire test suite to fail, requiring resets after each test.
Singletons are useful for achieving a global state, but modules might be a better alternative.
Chapter 4: Entire Test Suite
Testing singletons is difficult because they change the state globally.
Small modifications to a singleton can cause an entire test suite to fail.
Singletons must be reset after each test.
Consider using a module if it can achieve the same goal as a singleton in managing global state.
Chapter 5: Named Connection
Default export:
export default connectionWhen importing a default export, the name doesn't matter.
Example:
In
index.js:export default connection;In
test.js:import connection from './index.js';orimport databaseConnection from './index.js';
Named export:
export { connection }When importing a named export, the name must match.
Example:
In
index.js:export { connection };In
test.js:import { connection } from './index.js';
You can rename a named import using the
askeyword:import { connection as databaseConnection } from './index.js';
Chapter 6: Called Database Connection
The default keyword allows exporting a value without needing to worry about naming collisions in other files.
You can import the default export under any name without affecting the original export name.
Advantage of default export: Avoid naming collisions by renaming the import, especially if the original name is already in use in the importing file.
Chapter 7: Conclusion
Exercise: Create a singleton database connection class.
Common use case: Ensuring only one database connection exists in an application.
Class structure:
DatabaseConnectionclass withconnectanddisconnectmethods.Ensure only one instance can ever exist.
Make the instance non-modifiable and a single instance using the singleton pattern.