Что это такое
Паттерн Singleton гарантирует, что у класса есть ровно один экземпляр во всей программе, и даёт всем одну и ту же точку доступа к нему. Типичные синглтоны: конфигурация, пул соединений, логгер.
В TypeScript это получается почти бесплатно. Модуль загружается и выполняется один раз, и всё, что он создаёт, кэшируется и используется всеми последующими импортами. Поэтому значение, сохранённое на уровне модуля — включая static-поле класса — уже существует ровно один раз. Паттерн добавляет только две вещи: private constructor, чтобы никто не мог создать второй экземпляр, и статический метод доступа, который создаёт значение при первом использовании.
Пример: одна конфигурация для всех
Конфигурация загружается при первом вызове Config.getInstance() и больше никогда. Каждый вызывающий получает один и тот же объект.
Загрузить один раз и хранить в статическом поле
Строка «загрузка конфигурации» печатается только один раз, хотя Config.getInstance() вызывается дважды, а a === b доказывает, что оба вызывающих держат один и тот же объект. Оператор ??= присваивает значение, только если поле всё ещё равно undefined, а это и есть «создать при первом обращении».
Вывод: программа на TypeScript и захваченный вывод
class Config {
readonly appName: string
// Приватный: никакой код за пределами этого класса не может создать второй Config.
private constructor() {
console.log("загрузка конфигурации (происходит один раз)")
this.appName = "PromptCookbook"
}
// Единственный экземпляр хранится здесь: создаётся при первом использовании и сохраняется навсегда.
private static instance: Config | undefined
static getInstance(): Config {
Config.instance ??= new Config()
return Config.instance
}
}
const a = Config.getInstance()
const b = Config.getInstance()
console.log("приложение:", a.appName)
console.log("тот же экземпляр:", a === b)
Когда его использовать
Используйте его, когда чего-то действительно должно быть ровно одно: одна загруженная конфигурация, один пул соединений, один кэш — и создание обходится дорого или дубликаты будут конфликтовать.
Откажитесь от него, когда можно просто создать значение один раз в начале программы и передать его тем, кому оно нужно. Открытая передача зависимостей понятнее, чем глобальный доступ: синглтон — это крайнее средство, а не первое.
Плюсы и минусы
Плюсы: гарантированно единственный экземпляр; приватный конструктор делает второй невозможным; создание ленивое, поэтому ничего не строится, пока никто не попросит.
Минусы: это замаскированная глобальная переменная — скрытые зависимости усложняют чтение кода; в тестах его нелегко заменить подделкой, и один тест может оставить состояние для следующего; злоупотребление приводит к запутанным программам.