Шаблон проектирования синглтона

Одноэлементный шаблон - это шаблон проектирования программного обеспечения, который ограничивает создание класса одним «единственным» экземпляром. Это полезно, когда нужен ровно один объект для координации действий в системе. Термин происходит от математической концепции синглтона.

Критики считают синглтон анти-шаблоном в том смысле, что он часто используется в сценариях, где он не выгоден, вводит ненужные ограничения в ситуациях, когда единственный экземпляр класса фактически не требуется, и вводит глобальное состояние в приложение.

Что такое синглтон?

Синглтон - это шаблон проектирования, который позволяет гарантировать, что у класса есть только один экземпляр, обеспечивая при этом глобальную точку доступа к этому экземпляру. Шаблон синглтона решает две проблемы одновременно, нарушая единую ответственность Принцип:

  • Убедитесь, что в классе есть только один экземпляр:

Наиболее частой причиной этого является контроль доступа к какому-либо общему ресурсу, например, базе данных или файлу. Обратите внимание, что такое поведение невозможно реализовать с помощью обычного конструктора, поскольку вызов конструктора должен всегда возвращать новый объект по дизайну.

  • Предоставьте этому экземпляру глобальную точку доступа.

Как и глобальная переменная, шаблон Singleton позволяет вам получить доступ к какому-либо объекту из любой точки программы. Однако он также защищает этот экземпляр от перезаписи другим кодом.

В настоящее время шаблон синглтона стал настолько популярным, что люди могут называть что-то синглтоном, даже если он решает только одну из перечисленных проблем.

Используйте шаблон Singleton:

  • Должен быть один и только один экземпляр класса
  • Класс должен быть доступен клиентам
  • Класс не должен требовать параметров как часть своей конструкции.
  • Когда создание экземпляра обходится дорого, синглтон может улучшить производительность.

Решение

Все реализации синглтона имеют эти два общих шага:

  • Сделайте конструктор по умолчанию закрытым, чтобы предотвратить другие объекты
  • от использования оператора new с классом Singleton.
  • Создайте статический метод создания, который действует как конструктор. Под капотом этот метод вызывает частный конструктор для создания объекта и сохраняет его в статическом поле. Все последующие вызовы этого метода возвращают кэшированный объект.

Проблема: Регистратор

у нас есть простой регистратор, в котором мы сохраняем сообщение и дату как журнал в нашем файле журнала.

//typescript
class Logger {
    logs: any

    constructor() {
        this.logs = [];
    }

    get_log() {
        // return all logs
        return this.logs;
    }

    set_log(message: string) {
        // save message to logger 
        // it can be file or database
        this.logs.push(message)
    }
}

class LoggerSingleton {
    static instance: Logger;

    constructor() {
        if (!LogSingleton.instance) {
            LogSingleton.instance = new Logger;
        }
    }

    get_instance() {
        return LogSingleton.instance
    }
}
// this line always call the same instance of Logger
let logger = new LogSingleton().get_instance()
logger.set_log('Example Massage')
logger.get_log()

в этом примере «LoggerSingleton» устанавливает экземпляр «Logger», и тогда у нас везде есть только один экземпляр нашего Logger.

Синглтон в Node.js

в Node.js просто добавьте `module.exports` с новым экземпляром класса, а затем автоматически создайте только один экземпляр в нашей программе.

class Logger {

    constructor() {
        this.logs = [];
    }

    get_log() {
        // return all logs
        return this.logs;
    }

    set_log(message: string) {
        // save message to logger 
        // it can be file or database
        this.logs.push(message)
    }
}
module.exports = new Logger()

Проблема: подключение к базе данных

мы хотим один раз подключиться к базе данных в нашем приложении и использовать ее. это означает, что когда мы хотим использовать экземпляр базы данных, мы просто вызываем тот же экземпляр.

class Database {
    // The field for storing the singleton instance should be
    // declared static.
    
    private static instance: Database

    // The singleton's constructor should always be private to
    // prevent direct construction calls with the `new`
    // operator.
    
    private constructor(){
    }
    
    // The static method that controls access to the singleton 
    //instance
    public static getInstance() {
        if (this.instance == null) {
            this.instance = new Database()
        }
        return this.instance
    }
    
    // Finally, any singleton should define some business logic 
    // which can be executed on its instance.
    public query(sql) {
        // For instance, all database queries of an app go
        // through this method. Therefore, you can place
        // throttling or caching logic here.
        // ...
    }
}
class Application {
    main() {
        Database foo = Database.getInstance()
        foo.query("SELECT ...")
        // ...
        Database bar = Database.getInstance()
        bar.query("SELECT ...")
        // The variable `bar` will contain the same object as
        // the variable `foo`.
    }
}

Плюсы

  • Вы можете быть уверены, что у класса есть только один экземпляр.
  • Вы получаете глобальную точку доступа к этому экземпляру.
  • Одноэлементный объект инициализируется только при первом запросе.

Минусы

  • Нарушает Принцип единой ответственности. Шаблон решает сразу две проблемы.
  • Шаблон Singleton может маскировать плохой дизайн, например, когда компоненты программы слишком много знают друг о друге.
  • Этот шаблон требует особой обработки в многопоточной среде, чтобы несколько потоков не создавали одноэлементный объект несколько раз.
  • Модульное тестирование клиентского кода Singleton может оказаться трудным, поскольку многие тестовые среды полагаются на наследование при создании фиктивных объектов. Поскольку конструктор одноэлементного класса является частным и переопределение статических методов невозможно на большинстве языков, вам нужно будет подумать о творческом способе имитации одноэлементного класса. Или просто тесты не пишите. Или не используйте шаблон Singleton.

использованная литература