Так что синглтоны плохие, тогда что?

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

Вот реальный пример из крупного недавнего проекта, в котором я участвовал:

Приложение было толстым клиентом со многими отдельными экранами и компонентами, которые используют огромное количество данных из состояния сервера, которое не обновляется слишком часто. Эти данные были в основном кэшированы в элементе «менеджер» Singleton - опасном «глобальном состоянии». Идея состояла в том, чтобы иметь это место в приложении, которое хранит и синхронизирует данные, а затем все открытые новые экраны могут просто запрашивать большинство из них, не требуя повторных запросов на различные поддерживающие данные с сервера. Постоянное обращение к серверу потребует слишком большой пропускной способности - и я говорю о тысячах долларов дополнительных счетов в неделю в неделю, поэтому это было неприемлемо.

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

496 голосов | спросил Bobby Tables 27 Jam1000000amThu, 27 Jan 2011 03:00:19 +030011 2011, 03:00:19

13 ответов


739

Здесь важно различать отдельные экземпляры и шаблон дизайна Singleton .

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

Шаблон проектирования Singleton - это очень специфический тип одного экземпляра, в частности:

  • Доступно через глобальное статическое поле экземпляра;
  • Создается либо при инициализации программы, либо при первом доступе;
  • Нет открытого конструктора (не может напрямую создаваться);
  • Никогда явно не освобождается (неявно освобождается от завершения программы).

Именно из-за этого конкретного выбора дизайна шаблон вводит несколько потенциальных долгосрочных проблем:

  • Неспособность использовать абстрактные или интерфейсные классы;
  • Неспособность к подклассу;
  • Высокая связь между приложениями (трудно модифицировать);
  • Трудно проверить (не может подделывать /издеваться над модульными тестами);
  • Трудно распараллеливаться в случае изменчивого состояния (требуется обширная блокировка);
  • и т. д.

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

Что вы можете сделать вместо этого? Просто не используйте шаблон Singleton.

Цитата из вопроса:

  

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

У этой концепции есть имя, как вы вроде намекаете, но не уверены в этом. Он называется кешем . Если вы хотите получить удовольствие, вы можете назвать его «автономным кешем» или просто автономной копией удаленных данных.

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

Первое, что я хотел бы сделать, это выделить различные функциональные области кэша на отдельные интерфейсы. Например, допустим, вы создавали худший клон для YouTube на основе Microsoft Access:

                          MSAccessCache
                                â-²
                                |
              + ----------------- + ----------------- +
              | | |
         IMediaCache IProfileCache IPageCache
              | | |
              | | |
          Моя учетная запись Моя учетная запись MostPopularPage

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

Это называется Injection of Dependency , кстати; вам не нужно использовать Spring или какой-либо специальный контейнер IoC, только если ваш общий класс принимает свои зависимости от вызывающего вместо , создавая их самостоятельно или ссылка на глобальное состояние .

Почему вы должны использовать интерфейс на основе интерфейса? Три причины:

  1. Это упрощает чтение кода; вы можете четко понимать из интерфейсов точно , какие данные зависят от зависимых классов.

  2. Если и когда вы понимаете, что Microsoft Access не лучший выбор для базы данных, вы можете заменить его чем-то лучше - скажем, SQL Server.

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

Если вы хотите сделать это еще на один шаг, вы можете использовать контейнер IoC (инфраструктура DI), например Spring (Java) или Unity (.NET). Почти каждая инфраструктура DI будет делать свои собственныеуправление жизненным циклом и, в частности, позволяет вам определить конкретную службу как один экземпляр (часто называющий его «singleton», но это только для знакомства). В основном эти рамки избавляют вас от большей части работы обезьян, проходящей вручную по экземплярам, ​​но они не являются строго необходимыми. Вам не нужны специальные инструменты для реализации этого дизайна.

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

                                                        + - IMediaRepository
                                                        |
                          Кэш (общий) --------------- + - IProfileRepository
                                â-² |
                                | + - IPageRepository
              + ----------------- + ----------------- +
              | | |
         IMediaCache IProfileCache IPageCache
              | | |
              | | |
          Моя учетная запись Моя учетная запись MostPopularPage

Преимущество этого в том, что вам даже не нужно разрывать ваш экземпляр Cache, если вы решите реорганизовать; вы можете изменить, как Media хранится просто, подав ему альтернативную реализацию IMediaRepository. Если вы подумаете о том, как это сочетается, вы увидите, что он все еще только создает один физический экземпляр кэша, поэтому вам не нужно дважды извлекать одни и те же данные.

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

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

ответил Aaronaught 27 Jpm1000000pmThu, 27 Jan 2011 21:53:00 +030011 2011, 21:53:00
41

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

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

Вероятно, проблема в том, что зависимости между частями системы не настроены правильно, и это, вероятно, системно.

Почему экраны должны знать, где они получают свои данные? Почему экраны не снабжены объектом, который может выполнять свои запросы на данные (за которыми скрыт кеш)? Зачастую ответственность за создание экранов не централизована, и поэтому нет явной точки для ввода зависимостей.

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

Кроме того, важно very понять, что время жизни объекта может быть полностью отделено от того, как объект найден для использования.

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

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

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

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

ответил quentin-starin 27 Jam1000000amThu, 27 Jan 2011 03:17:55 +030011 2011, 03:17:55
37

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

TL; др:

Шаблон Gang of Four Singleton делает две вещи: дает вам удобный доступ к объекту из любого места и гарантирует, что может быть создан только один его экземпляр. 99% времени, все, о чем вы заботитесь, это первая половина этого, и картирование по второй половине, чтобы получить это, добавляет ненужные ограничения.

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

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

  • Отбросьте это полностью. Я видел много одноэлементных классов, которые не имеют никакого состояния и являются просто мешками вспомогательных функций. Те, кому вообще не нужен экземпляр. Просто сделайте их статическими функциями или переместите их в один из классов, который функция принимает в качестве аргумента. Вам не понадобится специальный класс Math, если вы можете просто сделать 123.Abs().

  • Пропустите его. Простое решение, если требуется какой-то другой метод, - это просто передать его. Нет ничего плохого в передаче некоторых объектов.

  • Поместите его в базовый класс. Если у вас много классов, которым всем нужен доступ к некоторому специальному объекту, и они разделяют базовый класс, вы можете сделать этот объект членом на базе. Когда вы его построите, перейдите в объект. Теперь производные объекты могут получить все, когда они в этом нуждаются. Если вы сделаете его защищенным, вы убедитесь, что объект все еще находится в инкапсулированном виде.

ответил munificent 27 Jpm1000000pmThu, 27 Jan 2011 22:47:22 +030011 2011, 22:47:22
20

Это не глобальное состояние как таковое.

На самом деле вам нужно только беспокоиться о глобальном изменяемом состоянии global mutable state

Основная проблема с singleton заключается в том, что он добавляет сцепление и, таким образом, делает такие вещи, как тестирование (er). Вы можете уменьшить сцепление, получив синглтон из другого источника (например, фабрики). Это позволит вам отделить код от конкретного экземпляра (хотя вы более тесно связаны с фабрикой (но, по крайней мере, завод может иметь альтернативные реализации для разных фаз)).

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

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

// Example from 5 minutes (con't be too critical)
class ServerFactory
{
    public:
        // By default return a RealServer
        ServerInterface& getServer();

        // Set a non default server:
        void setServer(ServerInterface& server);
};

class ServerInterface { /* define Interface */ };

class RealServer: public ServerInterface {}; // This is a singleton (potentially)

class TestServer: public ServerInterface {}; // This need not be.
ответил Martin York 27 Jam1000000amThu, 27 Jan 2011 03:13:27 +030011 2011, 03:13:27
14

Тогда что? Поскольку никто не сказал это: панель инструментов , То есть, если вы хотите глобальные переменные .

  

Синглтон злоупотребления можно избежать, посмотрев на проблему под другим углом. Предположим, что для приложения требуется только один экземпляр класса, и приложение настраивает этот класс при запуске: почему сам класс должен отвечать за одноэлемент? Для приложения вполне логично взять на себя эту ответственность, поскольку приложение требует такого поведения. Приложение, а не компонент, должно быть одиночным. Затем приложение делает экземпляр компонента доступным для любого используемого кода приложения. Когда приложение использует несколько таких компонентов, оно может объединить их в то, что мы назвали панель инструментов.

     

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

public class Toolbox {
     private static Toolbox _instance; 

     public static Toolbox Instance {
         get {
             if (_instance == null) {
                 _instance = new Toolbox(); 
             }
             return _instance; 
         }
     }

     protected Toolbox() {
         Initialize(); 
     }

     protected void Initialize() {
         // Your code here
     }

     private MyComponent _myComponent; 

     public MyComponent MyComponent() {
         get {
             return _myComponent(); 
         }
     }
     ... 

     // Optional: standard extension allowing
     // runtime registration of global objects. 
     private Map components; 

     public Object GetComponent (String componentName) {
         return components.Get(componentName); 
     }

     public void RegisterComponent(String componentName, Object component) 
     {
         components.Put(componentName, component); 
     }

     public void DeregisterComponent(String componentName) {
         components.Remove(componentName); 
     }

}

Но угадайте, что? Это синглтон!

А что такое singleton?

Возможно, здесь начинается путаница.

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

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

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

Не поймите меня неправильно!

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

Во всяком случае, есть много других предложений, кроме Toolbox, и так же, как панель инструментов, у каждого есть свое приложение ...

Другие альтернативы

  • лучшая статья, которую я только что прочитал о синглонах , предлагает Locator в качестве альтернативы. Для меня это в основном Static Toolbox ", если хотите. Другими словами, сделайте Service Locator Singleton и у вас есть Toolbox. Это противоречит его первоначальному предложению избегать синглтона, конечно, но это только для обеспечения того, чтобы синглтонская проблема заключалась в том, как она используется, а не сама по себе.

  • Другие предлагают Заводской шаблон в качестве альтернативы. Это была первая альтернатива, которую я слышал от коллеги, и мы быстро ее исключили для нашего использования в качестве global var . Он уверен, что его использование, но так же и синглтоны.

Обе альтернативы выше - хорошие альтернативы. Но все зависит от вашего использования.

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

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

Невозможность (для абстрактного или подкласса) действительно существует, но что? Это не для этого. Нет неспособности интерфейса , поскольку могу сказать . Связь с высоким также может быть там, но это только потому, что обычно используется. Он не должен . Фактически, связь сама по себе не имеет ничего общего с одноэлементным паттерном. При этом выясняется, что он также устраняет трудности тестирования. Что касается трудностей с распараллеливанием, это зависит от языка и платформы, поэтому опять же не проблема в шаблоне.

Практические примеры

Я часто вижу, что 2 используется, как в пользу, так и против одиночных. Веб-кеш (мой случай) и служба журнала .

Журнал, некоторые утвердят , является идеальным примером одноэлементности, потому что, и я цитирую:

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

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

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

ответил cregox 13 32013vEurope/Moscow11bEurope/MoscowWed, 13 Nov 2013 16:34:34 +0400 2013, 16:34:34
4

Синглтон не является фундаментальным способом bad , в том смысле, что любые расчетные вычисления могут быть хорошими или плохими. Он может быть только когда-либо правильным (дает ожидаемые результаты) или нет. Он также может быть полезен или нет, если он делает код более четким или более эффективным.

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

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

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

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

ответил SingleNegationElimination 27 Jam1000000amThu, 27 Jan 2011 07:32:37 +030011 2011, 07:32:37
4

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

Каждый компонент, который имеет зависимость от этого «менеджера», делает это, запрашивая его экземпляр singleton. И если вы хотите написать единичный тест для такого компонента, вам придется вводить данные в этот экземпляр singleton, что может быть нелегко.

Если, с другой стороны, ваш «менеджер» вводится в зависимые компоненты через параметр конструктора, а компонент не знает конкретного типа менеджера, только интерфейс или абстрактный базовый класс, который реализует менеджер, то единичный тест может предоставлять альтернативные реализации менеджера при тестировании зависимостей.

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

Но если вы не заботитесь об модульных тестах, то шаблон дизайна singleton может быть совершенно точным. (но я бы так не сделал)

ответил Pete 27 Jpm1000000pmThu, 27 Jan 2011 22:27:42 +030011 2011, 22:27:42
3

Использование одноэлементного шаблона, представляющего фактические объекты, вполне приемлемо. Я пишу для iPhone, и в системе Cocoa Touch есть много синглтонов. Само приложение представлено одним элементом класса UIApplication. Существует только одно приложение, поэтому уместно представить это с помощью singleton.

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

ответил Dan Ray 27 Jpm1000000pmThu, 27 Jan 2011 16:39:27 +030011 2011, 16:39:27
2

Синглтоны - это просто проекция ориентированной на обслуживание архитектуры в программу.

API - пример одноэлементного уровня на уровне протокола. Вы получаете доступ к Твиттеру, Google и т. Д. Через то, что по существу является однопользовательским. Итак, почему синглтоны становятся плохими в рамках программы?

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

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

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

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

Обычно я бы обернул класс XxxService, который обертывает singleton вокруг класса Xxx. Синглтон вообще не находится в классе Xxx, он отделен от другого класса, XxxService. Это связано с тем, что Xxx может иметь несколько экземпляров, хотя это маловероятно, но мы все же хотим иметь один экземпляр Xxx, глобально доступный для каждой системы. XxxService обеспечивает хорошее разделение проблем. Xxx не нужно применять политику singleton, но мы можем использовать Xxx как одноэлементный, когда нам нужно.

Что-то вроде:

 //XxxService.h:
/**
 * Provide singleton wrapper for Xxx object. This wrapper
 * can be autogenerated so is not made part of the object.
 */

#include "Xxx/Xxx.h"


class XxxService
{
    public:
    /**
     * Return a Xxx object as a singleton. The double check
     * singleton algorithm is used. A 0 return means there was
     * an error. Developers should use this as the access point to
     * get the Xxx object.
     *
     * <PRE>
     * @@ #include "Xxx/XxxService.h"
     * @@ Xxx* xxx= XxxService::Singleton();
     * <PRE>
     */

     static Xxx*     Singleton();

     private:
         static Mutex  mProtection;
};


//XxxService.cpp:

#include "Xxx/XxxService.h"                   // class implemented
#include "LockGuard.h"     

// CLASS SCOPE
//
Mutex XxxService::mProtection;

Xxx* XxxService::Singleton()
{
    static Xxx* singleton;  // the variable holding the singleton

    // First check to see if the singleton has been created.
    //
    if (singleton == 0)
    {
        // Block all but the first creator.
        //
        LockGuard lock(mProtection);

        // Check again just in case someone had created it
        // while we were blocked.
        //
        if (singleton == 0)
        {
            // Create the singleton Xxx object. It's assigned
            // to a temporary so other accessors don't see
            // the singleton as created before it really is.
            //
            Xxx* inprocess_singleton= new Xxx;

            // Move the singleton to state online so we know that is has
            // been created and it ready for use.
            //
            if (inprocess_singleton->MoveOnline())
            {
                LOG(0, "XxxService:Service: FAIL MoveOnline");
                return 0;
            }

            // Wait until the module says it's in online state.
            //
            if (inprocess_singleton->WaitTil(Module::MODULE_STATE_ONLINE))
            {
                LOG(0, "XxxService:Service: FAIL move to online");
                return 0;
            }

            // The singleton is created successfully so assign it.
            //
            singleton= inprocess_singleton;


        }// still not created
    }// not created

    // Return the created singleton.
    //
    return singleton;

}// Singleton  
ответил Todd Hoff 30 Jpm1000000pmThu, 30 Jan 2014 20:40:07 +040014 2014, 20:40:07
1

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

Что бы вы сделали, так это класс, но УДАЛИТЕ ВСЕ СТАТИЧЕСКИЕ ЧЛЕНЫ. Хорошо, это не обязательно, но я рекомендую его. На самом деле вы просто инициализируете класс, как обычный класс, и PASS указатель внутри. Не делайте frigen сказать ClassIWant.APtr (). LetMeChange.ANYTHINGATALL (). Andhave_no_structure ()

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

ответил 27 Jam1000000amThu, 27 Jan 2011 07:46:30 +030011 2011, 07:46:30
1

IMO, ваш пример звучит нормально. Я бы предложил факторинг следующим образом: кеш-объект для каждого (и за каждым) объекта данных; объекты кэша и объекты доступа db имеют один и тот же интерфейс. Это дает возможность обменивать кеши в коде и из него; плюс он дает легкий путь расширения.

Графический

DB
|
DB Accessor for OBJ A
| 
Cache for OBJ A
|
OBJ A Client requesting

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

Это отделяет вещи, поэтому вы можете добавлять новые кеши без необходимости входить и модифицировать объект Uber-Cache. YMMV. IANAL. ETC.

ответил Paul Nathan 27 Jpm1000000pmThu, 27 Jan 2011 23:13:20 +030011 2011, 23:13:20
1

Немного поздно для вечеринки, но в любом случае.

Синглтон - это инструмент в панели инструментов, как и все остальное. Надеюсь, у вас больше на вашем инструменте, чем на одном молотке.

Рассмотрим это:

public void DoSomething()
{
    MySingleton.Instance.Work();
}

против

public void DoSomething(MySingleton singleton)
{
    singleton.Work();
}
DoSomething(MySingleton.instance);

1-й случай приводит к высокой связи и т. д .; 2-й путь не имеет проблем. @Aaronaught описывает, насколько я могу судить. Его все о том, как вы его используете.

ответил Evgeni 10 TueEurope/Moscow2013-12-10T20:00:42+04:00Europe/Moscow12bEurope/MoscowTue, 10 Dec 2013 20:00:42 +0400 2013, 20:00:42
1

Приведите каждый экран в Менеджере в свой конструктор.

При запуске приложения вы создаете один экземпляр менеджера и передаете его.

Это называется Inversion of Control и позволяет вам менять контроллер при изменении конфигурации и в тестах. Кроме того, вы можете запускать несколько экземпляров приложения или частей своего приложения в параллельном режиме (полезно для тестирования!). Наконец, ваш менеджер умрет со своим собственным объектом (класс запуска).

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

ответил Alexander Torstling 30 Jpm1000000pmThu, 30 Jan 2014 21:48:49 +040014 2014, 21:48:49

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132