Singleton Design Pattern
Deep dive into the Singleton Design Pattern with real-world examples
This pattern ensures that a class has only one instance and provides a global point of access to that instance.
Real World Analogy
Think about the role of a President (or Prime Minister) in a country. A nation can have many citizens, many government officials, and many distinct government departments. However, at any given moment, there is only one President.
This role is a Singleton.

Left: Without Singleton: Different clients directly instantiate the object they need. This results in multiple instances existing at once, each possibly having different internal data. Right: With Singleton: All clients must go through a static gatekeeper method. This checks if the single instance already exists. If it does, it returns it; if not, it creates it once and then returns it.

-
PresidentSingletonClass: This central box defines the structure. -
-instance: PresidentSingleton(Static): A private, static variable that holds the reference to the single instance. The minus sign (-) means private. Static means it belongs to the class itself, not to objects of the class. It initializes tonull. -
-PresidentSingleton()(Private Constructor): This is critical. The constructor is private. This means external code cannot callnew PresidentSingleton(). The pattern works by blocking the standardnewkeyword. -
+getInstance(): PresidentSingleton(Public Static): This is the global access point. It is public, static. The plus sign (+) means public. The entire system uses this method to interact with the singleton. It manages the creation logic (if null, create; otherwise, return existing).
Working:
It involves the following steps:
- Private Constructor: Prevents instantiation from outside the class
- Static Variables: Holds the single instance of the class.
- Public Static Method: Provides a global access point to get the instance. There are 2 ways of implementing it:
- Eager Loading
- Lazy Loading
Eager Loading (Early Initialization)
The resource is instantiated upfront as soon as the module/class is executed:
class DatabaseConnection{
constructor() {
console.log("DB Connection Initialized");
}
query(sql){
return `Executing query: ${sql}`;
}
}
class EagerDatabaseService {
//Static Property initialized immediately
static instance = new DatabaseConnection();
static getInstance() {
return this.instance;
}
}
//Even before calling getInstance(), connection is already created
console.log("App Started");
const db = EagerDatabaseService.getInstance();
console.log(db.query("SELECT * FROM users"));
Lazy Loading
The resource is held as null until someone calls the accessor method, instantiating it only on demand:
class DatabaseConnection {
constructor() {
console.log("Database connection initialized!");
}
query(sql) {
return `Executing query: ${sql}`;
}
}
class LazyDatabaseService {
static #instance = null; // Starts empty
static getInstance() {
if (!this.#instance) {
console.log("Instance not found, creating now...");
this.#instance = new DatabaseConnection();
}
return this.#instance;
}
}
console.log("App started");
// Nothing is initialized yet!
// Instantiation happens here on the first request
const db1 = LazyDatabaseService.getInstance();
// Reuses the existing instance on subsequent requests
const db2 = LazyDatabaseService.getInstance();
console.log(db1 === db2); // true