Singletons - это горячо обсуждаемый шаблон проектирования, поэтому мне интересно, что о них думает сообщество Stack Overflow.
Пожалуйста, укажите причины своего мнения, а не просто "Singletons для ленивых программистов!"
Вот довольно хорошая статья по этому вопросу, хотя она против использования Singletons: Scientificninja.com: Performant-Singletons .
У кого-нибудь есть другие хорошие статьи на них? Может быть, в поддержку синглетонов?
Цель Singleton - обеспечить, чтобы у класса был только один экземпляр, и предоставить глобальную точку доступа к нему. В большинстве случаев основное внимание уделяется одной точке экземпляра. Представьте, если бы это называлось Globalton. Это звучит менее привлекательно, так как это подчеркивает (обычно) негативные коннотации глобальной переменной.
Большинство хороших аргументов против синглетов связано с трудностями, с которыми они сталкиваются при тестировании, так как создание для них двойников теста не так просто.
Синглтоны имеют свое применение, но нужно быть осторожным в их использовании и разоблачении, потому что их слишком легко злоупотреблять , трудно по-настоящему юнит-тестировать, и легко создавать круговые зависимости, основанные на двух синглетонах, которые обращаются друг к другу.
Это полезно, однако, когда вы хотите быть уверены, что все ваши данные синхронизированы между несколькими экземплярами, например, конфигурации для распределенного приложения, например, могут полагаться на одиночные пакеты, чтобы убедиться, что все соединения используют одинаковые до дата набор данных.
Синглтон - это просто набор глобальных переменных в модном костюме.
Глобальные переменные имеют свое применение, как и синглтоны, но если вы думаете, что вы делаете что-то крутое и полезное с одиночкой, вместо того, чтобы использовать грубую глобальную переменную (все знают, что глобальные перемены плохие mmkay), вы, к сожалению, введены в заблуждение.
У Google есть Singleton Detector для Java, который, как я считаю, изначально был инструментом, который должен запускаться для всего кода, созданного в Google. В двух словах причина для удаления Singletons:
потому что они могут затруднить тестирование и скрыть проблемы с вашим дизайном
Более подробное объяснение см. В разделе « Почему синглтоны противоречивы » от Google.
Я считаю, что вы должны быть очень осторожны с тем, почему вы решили использовать синглтон. Как уже упоминали другие, это по сути та же проблема, что и использование глобальных переменных. Вы должны быть очень осторожны и подумать, что вы могли бы сделать, используя один из них.
Их очень редко использовать, и обычно есть лучший способ сделать что-то. Я сталкивался с ситуациями, когда я что-то делал с помощью синглтона, а затем мне пришлось просеять свой код, чтобы вытащить его после того, как я обнаружил, насколько хуже это стало (или после того, как я придумал гораздо лучшее, более разумное решение). )
Я пытался придумать, как прийти на помощь бедному Сингелтону, но должен признать, что это сложно. Я видел очень немного законного их использования, и с нынешним диском для внедрения зависимостей и модульного тестирования их просто сложно использовать. Они определенно являются проявлением «культа груза» программирования с шаблонами проектирования. Я работал со многими программистами, которые никогда не взламывали книгу «GoF», но они знают «Сингелтон» и, следовательно, знают «Шаблоны».
Я должен не согласиться с Орионом, хотя, в большинстве случаев я видел, как синглтоны переусердствовали в том, что это не глобальные переменные в одежде, а скорее глобальные услуги (методы) в одежде. Интересно отметить, что если вы попытаетесь использовать Singelton в SQL Server 2005 в безопасном режиме через интерфейс CLR, система пометит код. Проблема в том, что у вас есть постоянные данные за пределами любой транзакции, которая может выполняться, конечно, если вы сделаете переменную экземпляра доступной только для чтения, вы сможете обойти проблему.
Эта проблема привела ко многим переделкам для меня за один год.
Я действительно не согласен с кучей глобальных переменных в причудливой идее. Синглтоны действительно полезны, когда используются для решения правильной проблемы. Позвольте мне привести вам реальный пример.
Однажды я разработал небольшую часть программного обеспечения для места, где я работал, и некоторые формы должны были использовать некоторую информацию о компании, ее сотрудниках, услугах и ценах. В своей первой версии система продолжала загружать эти данные из базы данных при каждом открытии формы. Конечно, вскоре я понял, что такой подход не самый лучший.
Затем я создал одноэлементный класс с именем company , который инкапсулировал все о месте, и к моменту открытия системы он был полностью заполнен данными.
Это был не просто набор переменных в причудливой одежде, потому что на него были возложены десятки обязанностей, например, связь с постоянным слоем для сохранения / извлечения данных о компании, работа с сотрудниками, сбор цен и т. Д.
Кроме того, это была фиксированная общесистемная легкодоступная точка для хранения данных компании.
Это был не просто набор переменных в причудливой одежде, потому что на него были возложены десятки обязанностей, например, связь с постоянным слоем для сохранения / извлечения данных о компании, работа с сотрудниками, сбор цен и т. Д.
Я должен сказать, что вы на самом деле не описывая Somthing, который должен быть единым объектом и это спорно, что любой из них, кроме сериализации данных должен был singelton.
Я вижу по крайней мере 3 набора классов, в которых я обычно проектирую, но я предпочитаю отдавать предпочтение более мелким более простым объектам, которые очень хорошо выполняют узкий набор задач. Я знаю, что это не природа большинства программистов. (Да, я работаю над 5000 строчными монстрами каждый день, и я особенно люблю 1200-строчные методы, которые пишут некоторые люди.)
Я думаю, дело в том, что в большинстве случаев вам не нужен сингелтон, а зачастую вы просто усложняете свою жизнь.
Священные войны! Хорошо, дайте мне посмотреть .. Последний раз, когда я проверял дизайн полиции сказал ..
Синглеты плохие, потому что они мешают автоматическому тестированию - экземпляры не могут быть созданы заново для каждого теста. Вместо этого логика должна быть в классе (A), который может быть легко создан и протестирован. Другой класс (B) должен отвечать за ограничение создания. Единый принцип ответственности на первый план! Это должно быть командное знание, что вы должны пройти через B, чтобы получить доступ к A - своего рода командное соглашение.
Я согласен в основном ..
Я думаю, что существует большое недопонимание по поводу использования шаблона Синглтона. Большинство комментариев здесь называют это местом для доступа к глобальным данным. Здесь нужно быть осторожным - синглтон как образец не для доступа к глобальным.
Синглтон должен использоваться только для одного экземпляра данного класса. Хранилище шаблонов имеет отличную информацию о Синглтоне .
Я использовал синглеты несколько раз в связке со Spring и не считал это опорой или ленивостью.
Этот шаблон позволил мне создать один класс для набора значений типа конфигурации, а затем разделить один (не изменяемый) экземпляр этого конкретного экземпляра конфигурации между несколькими пользователями моего веб-приложения.
В моем случае синглтон содержал критерии конфигурации клиента - местоположение файла CSS, критерии подключения БД, наборы функций и т. Д. - специфичные для этого клиента. Эти классы были созданы и доступны через Spring и использовались пользователями с одинаковой конфигурацией (т.е. 2 пользователями из одной компании). * ** Я знаю, что есть название для этого типа приложения, но оно ускользает от меня *
Я чувствую, что было бы расточительно создавать (а затем собирать мусор) новые экземпляры этих «постоянных» объектов для каждого пользователя приложения.
Синглтоны очень полезны, и использование их само по себе не является анти-паттерном. Тем не менее, они получили плохую репутацию в значительной степени потому, что вынуждают любой потребительский код признавать, что они являются единым целым для взаимодействия с ними. Это означает, что если вам когда-нибудь понадобится их «отсоединить», влияние на вашу кодовую базу может быть очень значительным.
Вместо этого я бы предложил либо спрятать Синглтон за фабрикой. Таким образом, если вам нужно изменить поведение экземпляра службы в будущем, вы можете просто изменить фабрику, а не все типы, которые используют Singleton.
Еще лучше использовать инверсию контрольного контейнера! Большинство из них позволяют вам отделить поведение экземпляров от реализации ваших классов.
В защиту синглетонов:
- Они не так плохи, как глобальные, потому что глобальные не имеют стандартного порядка инициализации, и вы можете легко увидеть недетерминированные ошибки из-за наивных или неожиданных порядков зависимости. Синглтоны (при условии, что они размещены в куче) создаются после всех глобальных переменных и в очень предсказуемом месте в коде.
- Они очень полезны для систем с ленивым ресурсом / кэшированием, таких как интерфейс для медленного устройства ввода-вывода. Если вы разумно создадите одноэлементный интерфейс для медленного устройства, и никто никогда не звонит, вы не потеряете время. Если другой фрагмент кода вызывает его из нескольких мест, ваш синглтон может оптимизировать кэширование для обоих одновременно и избежать двойного поиска. Вы также можете легко избежать любых тупиковых ситуаций на одноэлементном ресурсе.
Против синглетонов:
- В C ++ нет хорошего способа автоматической очистки после синглетонов. Есть обходные пути и немного хакерские способы сделать это, но просто не существует простого, универсального способа убедиться, что деструктор вашего синглтона всегда вызывается. Это не так ужасно для памяти - просто подумайте об этом как о более глобальных переменных для этой цели. Но это может быть плохо, если ваш синглтон выделяет другие ресурсы (например, блокирует некоторые файлы) и не освобождает их.
Мое собственное мнение:
Я использую синглтоны, но избегайте их, если есть разумная альтернатива. До сих пор это работало хорошо для меня, и я нашел, что они могут быть проверены, хотя немного больше работы для тестирования.
class MySingleton { public: static MySingleton &getInstance() { static MySingleton instance; return instance; } private: MySingleton(); ~MySingleton(); };
, Ссылка - stackoverflow.com/questions/2593324/c-singleton-classВ блоге Google Testing есть три довольно хороших сообщения в блоге о Singletons Мишко Хевери .
Самая большая проблема с одноплодным что они делают модульное тестирование трудно , особенно , если вы хотите запустить тесты параллельно , но независимо.
Во-вторых, люди часто считают, что ленивая инициализация с двойной проверкой блокировки является хорошим способом их реализации.
Наконец, если ваши синглтоны не являются неизменяемыми, они могут легко стать проблемой производительности, когда вы попытаетесь масштабировать ваше приложение для работы в нескольких потоках на нескольких процессорах. Согласованная синхронизация стоит дорого в большинстве сред.
Например, в синглетах, например, в Java, страшно то, что в некоторых случаях вы можете получить несколько экземпляров одного и того же синглтона. JVM однозначно идентифицирует на основе двух элементов: полное имя класса и загрузчик классов, ответственный за его загрузку.
Это означает, что один и тот же класс может быть загружен двумя загрузчиками классов, не подозревающими друг друга, и разные части вашего приложения будут иметь разные экземпляры этого синглтона, с которыми они взаимодействуют.
Один из моих коллег был очень одинок. Когда бы ни было что-то вроде менеджера или босса, как объект, он превращал это в синглтон, потому что полагал, что должен быть только один босс. И каждый раз, когда система предъявляла какие-то новые требования, выяснялось, что существуют совершенно веские причины для разрешения нескольких экземпляров.
Я бы сказал, что синглтон следует использовать, если модель предметной области диктует (а не «предполагает»), что она существует. Все остальные случаи являются просто единичными экземплярами класса.
Пишите нормальные, тестируемые, инъецируемые объекты и позволяйте Guice / Spring / что угодно обрабатывать создание экземпляров Шутки в сторону.
Это применимо даже в случае кэшей или любых других естественных вариантов использования синглетонов. Нет необходимости повторять весь ужас написания кода, чтобы попытаться применить один экземпляр. Позвольте вашей структуре внедрения зависимости обработать это. (Я рекомендую Guice для облегченного DI-контейнера, если вы его еще не используете).
Синглтон как деталь реализации в порядке. Синглтон в качестве интерфейса или в качестве механизма доступа представляет собой гигантскую PITA.
Статический метод, который не принимает параметров, возвращающих экземпляр объекта, лишь немного отличается от простого использования глобальной переменной. Если вместо этого объект имеет ссылку на переданный одноэлементный объект, через конструктор или другой метод, то не имеет значения, как на самом деле создается синглтон, и весь шаблон оказывается неважным.
Многие приложения требуют наличия только одного экземпляра некоторого класса, поэтому полезно иметь только один экземпляр класса. Но есть варианты того, как шаблон реализован .
Существует статический синглтон , в котором класс предписывает, что может быть только один экземпляр класса на процесс (в Java фактически один на ClassLoader). Другой вариант - создать только один экземпляр .
Статические синглтоны - зло - один из видов глобальных переменных. Они затрудняют тестирование, потому что невозможно выполнить тесты в полной изоляции. Вам необходим сложный код настройки и очистки для очистки системы между каждым тестом, и очень легко забыть правильно очистить некоторое глобальное состояние, что, в свою очередь, может привести к неопределенному поведению в тестах.
Создание только одного экземпляра - это хорошо . Вы просто создаете один экземпляр при запуске программы, а затем передаете указатель на этот экземпляр всем другим объектам, которые в этом нуждаются. Инфраструктуры внедрения зависимостей делают это легко - вы просто настраиваете область объекта, а структура DI позаботится о создании экземпляра и передаче его всем, кто в нем нуждается. Например, в Guice вы должны аннотировать класс с помощью @Singleton, а структура DI создаст только один экземпляр класса (для каждого приложения - в одной JVM может быть запущено несколько приложений). Это облегчает тестирование, потому что вы можете создать новый экземпляр класса для каждого теста и позволить сборщику мусора уничтожить экземпляр, когда он больше не используется. Ни одно глобальное состояние не будет передаваться из одного теста в другой.
Для получения дополнительной информации: Чистые переговоры по коду - «Глобальное государство и синглтоны»
Синглтон - не ужасная модель, хотя он часто используется неправильно . Я думаю, что это неправильное использование, потому что это один из самых простых шаблонов, и большинство новых для синглтона привлекает глобальный побочный эффект.
Эрих Гамма сказал, что синглтон - это шаблон, который, как он хотел, не был включен в книгу GOF, и это плохой дизайн. Я склонен не соглашаться
Если шаблон используется для создания единственного экземпляра объекта в любой момент времени, тогда шаблон используется правильно. Если синглтон используется для того, чтобы дать глобальный эффект, он используется неправильно.
Недостатки:
- Вы соединяетесь с одним классом по всему коду, который вызывает singleton
- Создает трудности с модульным тестированием, поскольку сложно заменить экземпляр на фиктивный объект
- Если код необходимо реорганизовать позже из-за необходимости более чем одного экземпляра, это более болезненно, чем если бы класс singleton был передан в объект (используя интерфейс), который его использует
Преимущества:
- Один экземпляр класса представлен в любой данный момент времени.
- По замыслу вы обеспечиваете это
- Экземпляр создается, когда это необходимо
- Глобальный доступ является побочным эффектом
Птенцы копают меня, потому что я редко использую синглтон, и когда я делаю это, обычно что-то необычное. Нет, серьезно, я люблю шаблон синглтона. Ты знаешь почему? Потому что:
- Мне лень.
- Ничто не может пойти не так.
Несомненно, «эксперты» расскажут о «модульном тестировании» и «инъекции зависимостей», но это все нагрузка на почки динго. Вы говорите, что синглтон трудно для модульного тестирования? Нет проблем! Просто объявите все публично и превратите свой класс в веселый дом всемирного добра. Вы помните шоу Highlander из 1990-х? Синглтон вроде как, потому что: A. Он никогда не умрет; и Б. Там может быть только один. Так что перестаньте слушать всех этих ди-джеев и реализуйте свой синглтон без промедления. Вот еще несколько веских причин ...
- Все делают это.
- Шаблон синглтона делает вас непобедимым.
- Синглтон рифмуется с «победа» (или «веселье» в зависимости от вашего акцента).
Я много читаю о «Синглтоне», его проблемах, когда его использовать и т. Д., И вот мои выводы до сих пор:
Неразбериха между классической реализацией Singleton и реальным требованием: ПРОСТО ОДИН МОМЕНТ КЛАССА!
Это вообще плохо реализовано. Если вам нужен уникальный экземпляр, не используйте (анти) шаблон использования статического метода GetInstance (), возвращающего статический объект. Это делает класс ответственным за создание одного экземпляра самого себя, а также за выполнение логики. Это нарушает принцип единой ответственности . Вместо этого это должно быть реализовано классом фабрики, ответственным за обеспечение существования только одного экземпляра.
Он используется в конструкторах, потому что он прост в использовании и не должен передаваться в качестве параметра. Это должно быть решено с помощью внедрения зависимостей , что является отличным шаблоном для создания хорошей и тестируемой объектной модели.
Не TDD . Если вы делаете TDD, зависимости извлекаются из реализации, потому что вы хотите, чтобы ваши тесты были легко написаны. Это делает вашу объектную модель лучше. Если вы используете TDD, вы не напишите статический GetInstance =). Кстати, если вы будете думать об объектах с четкими обязанностями вместо классов, вы получите тот же эффект =).