Синглтон: как его использовать - PullRequest
288 голосов
/ 17 сентября 2008

Edit: От другого вопроса я предоставил ответ, который содержит ссылки на множество вопросов / ответов о синглетонах: Подробнее о синглетонах здесь:

Итак, я прочитал ветку Синглтоны: хороший дизайн или костыль?
И аргумент все еще бушует.

Я вижу синглтоны как шаблон дизайна (хороший и плохой).

Проблема синглтона не в шаблоне, а в пользователях (извините всех). Все и их отец думают, что могут правильно их реализовать (а из многих интервью, которые я провел, большинство людей не могут). Кроме того, поскольку все думают, что они могут реализовать правильный Singleton, они используют шаблон и используют его в ситуациях, которые не подходят (замена глобальных переменных на Singletons!).

Итак, основные вопросы, на которые необходимо ответить:

  • Когда следует использовать синглтон
  • Как правильно реализовать Singleton

Я надеюсь, что в этой статье мы сможем собрать вместе в одном месте (вместо того, чтобы гуглить и искать на нескольких сайтах) авторитетный источник того, когда (а затем и как) правильно использовать Singleton. Также уместным будет список Анти-Использований и распространенных плохих реализаций, объясняющих, почему они не работают, и для хороших реализаций их слабые стороны.


Так что качайте шарик:
Я подниму руку и скажу, что это то, что я использую, но, вероятно, у меня проблемы.
Мне нравится, как Скотт Майерс рассматривает эту тему в своих книгах "Эффективный C ++"

Хорошие ситуации для использования синглетонов (не много):

  • Каркасы логирования
  • Нитки для утилизации бассейнов
/*
 * C++ Singleton
 * Limitation: Single Threaded Design
 * See: http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
 *      For problems associated with locking in multi threaded applications
 *
 * Limitation:
 * If you use this Singleton (A) within a destructor of another Singleton (B)
 * This Singleton (A) must be fully constructed before the constructor of (B)
 * is called.
 */
class MySingleton
{
    private:
        // Private Constructor
        MySingleton();
        // Stop the compiler generating methods of copy the object
        MySingleton(MySingleton const& copy);            // Not Implemented
        MySingleton& operator=(MySingleton const& copy); // Not Implemented

    public:
        static MySingleton& getInstance()
        {
            // The only instance
            // Guaranteed to be lazy initialized
            // Guaranteed that it will be destroyed correctly
            static MySingleton instance;
            return instance;
        }
};

OK. Давайте вместе возьмем критику и другие реализации.
: -)

Ответы [ 24 ]

3 голосов
/ 01 августа 2009

Поскольку синглтон позволяет создавать только один экземпляр, он эффективно контролирует репликацию экземпляров. например, вам не понадобится несколько экземпляров поиска - например, карта поиска Морзе, поэтому можно обернуть ее в одноэлементный класс. И только то, что у вас есть один экземпляр класса, не означает, что вы также ограничены количеством ссылок на этот экземпляр. Вы можете ставить в очередь вызовы (чтобы избежать проблем с потоками) к экземпляру и вносить необходимые изменения. Да, общая форма синглтона является общедоступной, вы, безусловно, можете изменить дизайн, чтобы создать синглтон с более ограниченным доступом. Я не уставал раньше, но уверен, что это возможно. И всем тем, кто прокомментировал, что шаблон синглтона является абсолютно злым, вы должны знать это: да, это зло, если вы не используете его должным образом или в рамках него ограничены эффективной функциональностью и предсказуемым поведением: не ОБОБЩАЙТЕ.

3 голосов
/ 17 сентября 2008

Синглтоны удобны, когда вы запускаете много кода, когда вы инициализируете и возражаете. Например, когда вы используете iBatis при настройке объекта персистентности, он должен прочитать все конфиги, проанализировать карты, убедиться, что все правильно, и т. Д., Прежде чем перейти к вашему коду.

Если бы вы делали это каждый раз, производительность сильно снизилась бы. Используя его в одиночку, вы принимаете этот удар один раз, а затем все последующие вызовы не должны это делать.

3 голосов
/ 17 сентября 2008

Настоящим недостатком синглетонов является то, что они нарушают наследование. Вы не можете получить новый класс для расширенной функциональности, если у вас нет доступа к коду, на который ссылается Singleton. Таким образом, помимо факта, что Singleton сделает ваш код тесно связанным (исправимо с помощью паттерна стратегии ... он же Dependency Injection), он также не позволит вам закрывать части кода от ревизии (совместно используемые библиотеки).

Так что даже примеры регистраторов или пулов потоков недопустимы и должны быть заменены стратегиями.

2 голосов
/ 17 сентября 2008

Но когда мне нужно что-то вроде синглтона, мне часто приходится использовать счетчик Шварца для его создания.

1 голос
/ 11 августа 2018

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

#include<iostream>
#include<mutex>

using namespace std;
std::mutex mtx;

class MySingleton{
private:
    static MySingleton * singletonInstance;
    MySingleton();
    ~MySingleton();
public:
    static MySingleton* GetInstance();
    MySingleton(const MySingleton&) = delete;
    const MySingleton& operator=(const MySingleton&) = delete;
    MySingleton(MySingleton&& other) noexcept = delete;
    MySingleton& operator=(MySingleton&& other) noexcept = delete;
};

MySingleton* MySingleton::singletonInstance = nullptr;
MySingleton::MySingleton(){ };
MySingleton::~MySingleton(){
    delete singletonInstance;
};

MySingleton* MySingleton::GetInstance(){
    if (singletonInstance == NULL){
        std::lock_guard<std::mutex> lock(mtx);
        if (singletonInstance == NULL)
            singletonInstance = new MySingleton();
    }
    return singletonInstance;
}

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

1 голос
/ 17 сентября 2008

Я использую Singletons в качестве собеседования.

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

0 голосов
/ 28 июля 2018

Если вы тот, кто создал синглтон и использует его, не делайте его синглтоном (это не имеет смысла, поскольку вы можете контролировать особенность объекта, не делая его синглтоном), но это имеет смысл, когда вы разработчик библиотеки, и вы хотите предоставить пользователям только один объект (в данном случае вы - тот, кто создал синглтон, но не пользователь).

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

0 голосов
/ 18 октября 2017

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

Я уверен, что есть и другие решения, но я считаю это очень полезным и простым в реализации.

0 голосов
/ 31 января 2014

Я до сих пор не понимаю, почему синглтон должен быть глобальным.

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

Я не понимаю, почему эта функциональность была бы плохой.

0 голосов
/ 07 января 2012

Еще одна реализация

class Singleton
{
public:
    static Singleton& Instance()
    {
        // lazy initialize
        if (instance_ == NULL) instance_ = new Singleton();

        return *instance_;
    }

private:
    Singleton() {};

    static Singleton *instance_;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...