Configuration Management
A single source of truth for application settings.
Ce contenu n’est pas encore disponible dans votre langue.
The Singleton is a creational design pattern that ensures a class has only one instance and provides a global point of access to it. It is widely used for managing shared resources like configurations, database connections, or logging services.
The Singleton pattern restricts the instantiation of a class to a single instance and provides a global point of access to it. This is useful when exactly one object is needed to coordinate actions across the system.
Configuration Management
A single source of truth for application settings.
Database Connection
A single connection instance to prevent resource leaks.
Shared Cache
Avoid data duplication in memory.
Centralized Logging
A single logger for the entire application.
| Advantages ✅ | Disadvantages ❌ |
|---|---|
| Strict control over instantiation. | Hard to test (shared global state). |
| Global access to the unique instance. | Can introduce hidden dependencies. |
| Resource efficiency (e.g., a single database connection). | Thread safety issues if poorly implemented. |
A non-thread-safe Singleton can create multiple instances if two threads instantiate it simultaneously. While JavaScript/TypeScript is single-threaded, understanding best practices is crucial for asynchronous environments.
class Singleton { private static instance: Singleton | null = null; private constructor() {} public static getInstance(): Singleton { if (!Singleton.instance) { Singleton.instance = new Singleton(); } return Singleton.instance; }}✅ Simple and effective in single-threaded environments.
class Singleton { private static instance: Singleton = new Singleton(); private constructor() {} public static getInstance(): Singleton { return Singleton.instance; }}✅ Thread-safe (instance is created when the class is loaded). ❌ Less performant if the instance is not always used.
class Singleton { private static instance: Singleton | null = null; private constructor() {} public static getInstance(): Singleton { if (!Singleton.instance) { if (!Singleton.instance) { Singleton.instance = new Singleton(); } } return Singleton.instance; }}✅ Thread-safe and performant.
class Database { private static instance: Database; private constructor() { console.log("Connecting to the database..."); } public static getInstance(): Database { if (!Database.instance) { Database.instance = new Database(); } return Database.instance; } public query(sql: string): void { console.log(`Executing: ${sql}`); }}
// Usageconst db1 = Database.getInstance();const db2 = Database.getInstance();console.log(db1 === db2); // true (same instance)public class Singleton { private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; }}
// UsageSingleton singleton1 = Singleton.getInstance();Singleton singleton2 = Singleton.getInstance();System.out.println(singleton1 == singleton2); // true (same instance)class Singleton { private static $instance = null;
private function __construct() {}
public static function getInstance() { if (self::$instance === null) { self::$instance = new Singleton(); } return self::$instance; }}
// Usage$singleton1 = Singleton::getInstance();$singleton2 = Singleton::getInstance();var_dump($singleton1 === $singleton2); // true (same instance)use std::sync::Mutex;
struct Singleton { value: i32,}
impl Singleton { fn new() -> Self { Singleton { value: 0 } }
fn get_instance() -> &'static Mutex<Singleton> { static INSTANCE: Mutex<Singleton> = Mutex::new(Singleton::new()); &INSTANCE }}
// Usagelet singleton = Singleton::get_instance();let mut singleton = singleton.lock().unwrap();singleton.value = 42;let instance = null;class Store { constructor() { if (!instance) { this.state = { count: 0 }; instance = this; } return instance; } increment() { this.state.count++; }}export const store = new Store();<script setup>import { store } from './store';store.increment();console.log(store.state.count); // 1</script>Use Lazy Initialization
Lazy initialization is simple and effective for most JavaScript/TypeScript applications.
Avoid Global State
Minimize the use of global state to make your application more testable.
Document the Singleton
Clearly document the Singleton’s purpose and usage to avoid misuse.
Consider Alternatives
In many cases, a simple object literal or module can replace a Singleton.
Let’s build a simple logging service using the Singleton pattern:
class Logger {private static instance: Logger;private logs: string[] = [];
private constructor() {}
public static getInstance(): Logger {if (!Logger.instance) {Logger.instance = new Logger();}return Logger.instance;}
public log(message: string): void {this.logs.push(message);console.log(message);}
public getLogs(): string[] {return this.logs;}}
// Usageconst logger1 = Logger.getInstance();const logger2 = Logger.getInstance();
logger1.log("Application started.");logger2.log("User logged in.");
console.log(logger1.getLogs()); // ["Application started.", "User logged in."]