Singleton Pattern
Ensures a class has only one instance and provides a global point of access to it. The Singleton pattern restricts instantiation of a class to a single object, which is useful when exactly one object is needed to coordinate actions across the system.
✦ Problem
Some classes should have exactly one instance. A global variable can provide access, but it doesn't prevent you from creating multiple instances. Additionally, solutions like global variables pollute the namespace and can be overwritten at any point.
✦ Solution
Make the default constructor private and create a static creation method that acts as a constructor. This method calls the private constructor to create an object and saves it in a static field. All following calls to this method return the cached object. The Singleton pattern lets you access the same object from anywhere in the program while protecting that instance from being overwritten by other code.
Participants
| Role | Responsibility |
|---|---|
| Singleton | Defines a static getInstance() method that returns the same instance of its own class. The constructor is hidden from client code. |
TypeScript Example
class Database {
private static instance: Database;
private connection: string;
private constructor(uri: string) {
this.connection = uri;
console.log("Connected to", uri);
}
static getInstance(uri = "mongodb://localhost"): Database {
if (!Database.instance) {
Database.instance = new Database(uri);
}
return Database.instance;
}
query(sql: string): string {
return `Executing "${sql}" on ${this.connection}`;
}
}
const db1 = Database.getInstance();
const db2 = Database.getInstance();
console.log(db1 === db2); // trueReal-World Example
A database connection pool is a classic real-world Singleton. An application typically needs one shared pool that manages a limited number of connections. Creating multiple pools would waste resources and potentially exceed connection limits. Similarly, logging frameworks, configuration managers, and thread pools use the Singleton pattern to ensure a single coordinated instance across the application.
✓ When to Use
- •A class should have a single instance available to all clients
- •You need stricter control over global variables
- •Managing shared resources like database connections or file systems
- •Coordinating system-wide actions from a single place
✗ When Not to Use
- •Unit testing becomes difficult because the Singleton carries state between tests
- •The pattern violates the Single Responsibility Principle by controlling its own creation and lifecycle
- •When multi-threaded environments require special treatment to prevent multiple threads from creating separate instances
- •If the class has many reasons to change, coupling everything through a Singleton amplifies the impact of changes
Understanding the Singleton Pattern
The Singleton pattern is one of the most important creational design patterns in object-oriented software design. Originally cataloged by the Gang of Four (Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides) in their seminal 1994 book "Design Patterns: Elements of Reusable Object-Oriented Software," this pattern continues to be a cornerstone of modern software architecture.
Ensures a class has only one instance and provides a global point of access to it. The Singleton pattern restricts instantiation of a class to a single object, which is useful when exactly one object is needed to coordinate actions across the system. The pattern involves the following key participants: Singleton. Each participant has a well-defined role, and the interactions between them create a flexible, maintainable structure that can evolve with changing requirements.
In TypeScript and modern JavaScript development, the Singleton pattern is particularly valuable because the language's type system and interface support allow you to express the pattern with compile-time safety. TypeScript generics can make Singleton implementations even more flexible and reusable while maintaining strong type checking throughout the pattern's structure.
Knowing when to apply the Singleton pattern is as important as knowing how. Common use cases include: A class should have a single instance available to all clients; You need stricter control over global variables; Managing shared resources like database connections or file systems. However, overusing design patterns can lead to unnecessarily complex code. Always evaluate whether the pattern genuinely solves your problem or if a simpler approach would suffice.
The Singleton pattern is related to several other design patterns: Factory Method, Abstract Factory, Builder, Prototype. Understanding these relationships helps you choose the right pattern for your specific situation and combine patterns effectively when building complex systems.
Related Patterns
Defines an interface for creating an object, but lets subclasses decide which class to instantiate. Factory Method lets …
Provides an interface for creating families of related or dependent objects without specifying their concrete classes. A…
Separates the construction of a complex object from its representation, allowing the same construction process to create…
Creates new objects by copying an existing object, known as the prototype. This pattern is useful when creating an insta…
More Creational Patterns
Explore All Design Patterns
Browse our complete reference of 23 design patterns with TypeScript examples, UML participants, and practical guidance.