Singleton
Ensure a class has only one instance and provide a global point of access to it.
Intent
Restrict the instantiation of a class to a single object and provide a well-known access point for that instance, ensuring coordinated access to a shared resource.
Problem
Multiple parts of your application need access to the same shared resource — such as a configuration store, connection pool, or logging service — but creating multiple instances would cause conflicts, duplicated state, or wasted resources. There is no built-in language mechanism to guarantee a single instance while still allowing lazy initialization.
Solution
Make the default constructor private and provide a static creation method that acts as the constructor. On the first call it creates the instance and caches it; on subsequent calls it returns the cached instance. Thread safety must be considered in concurrent environments.
Participants
- Singleton — the class that manages its own unique instance and provides a static accessor
- Client — any code that obtains the instance through the static accessor rather than direct construction
Advantages
- Guarantees that only one instance of the class exists throughout the application lifetime
- Provides a global access point to that instance without relying on global variables
- The instance is created only when first requested, enabling lazy initialization
Disadvantages
- Violates the Single Responsibility Principle by coupling instance management with business logic
- Can mask bad design by hiding dependencies instead of making them explicit via constructor injection
- Makes unit testing difficult because the global state persists between tests
- Requires special handling in multi-threaded environments to avoid race conditions during initialization
Real-World Analogy
A country has exactly one government. Regardless of the personal identities of the individuals who form governments, the title 'The Government of X' is a global point of access that identifies the group in charge. You don't create a new government each time someone needs to interact with it — you access the existing one.
Use Cases
- Database connection pool shared across an application
- Application-wide configuration or settings registry
- Centralized logging service
- Hardware interface access such as a printer spooler
- Caching layer that must be consistent across modules
Code Examples
Thread-safe singleton using a private constructor and a static getInstance method with lazy initialization. TypeScript's module system naturally runs once, so the class-based approach is mainly useful when you need controlled, deferred creation.
Related Patterns
Factory Method
Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.