Синглтоны: хороший дизайн или костыль?

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

Пожалуйста, укажите причины своего мнения, а не просто "Singletons для ленивых программистов!"

Вот довольно хорошая статья по этому вопросу, хотя она против использования Singletons: Scientificninja.com: Performant-Singletons.

У кого-нибудь есть другие хорошие статьи на них? Может быть, в поддержку Singletons?

Ответ 1

В защиту одиночек:

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

Против одиночных:

  • В С++ нет хорошего способа автоматической очистки после синглтонов.. Есть рабочие и немного хакерские способы сделать это, но просто нет простого, универсального способа сделать уверен, что ваш однотонный деструктор всегда называется. Это не так страшно по памяти - просто подумайте об этом как о более глобальных переменных, для этой цели. Но это может быть плохо, если ваш singleton выделяет другие ресурсы (например, блокирует некоторые файлы) и не освобождает их.

Мое собственное мнение:

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

Ответ 2

В Google есть Singleton Detector для Java, который, как я считаю, был запущен как инструмент, который должен запускаться во всем коде, созданный в Google. Разумная причина для удаления синглтонов:

потому что они могут проводить тестирование трудно и скрыть проблемы с вашим дизайн

Для более явного объяснения см. " Почему синглтоны противоречивы от Google.

Ответ 3

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

Глобальные переменные используют их, как и одиночные, но если вы считаете, что делаете что-то классное и полезное с помощью одноэлементного, вместо того, чтобы использовать глобальную переменную yucky (все знают, что глобальные переменные плохие mmkay), вы, к сожалению, введены в заблуждение.

Ответ 4

Цель Singleton - обеспечить, чтобы класс имел только один экземпляр и обеспечивал глобальную точку доступа к нему. В большинстве случаев основное внимание уделяется точке одного экземпляра. Представьте себе, если бы это называлось Глобалтоном. Это звучит менее привлекательно, поскольку это подчеркивает (обычно) отрицательные коннотации глобальной переменной.

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

Ответ 6

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

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

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

Недостатки:

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

Преимущества:

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

Ответ 7

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

  • Я ленивый.
  • Ничто не может пойти не так.

Разумеется, "эксперты" бросят вокруг кучу разговоров об "модульном тестировании" и "инъекции зависимостей", но все загружают почки динго. Вы говорите, что синглтон трудно unit test? Нет проблем! Просто объявите все публичным и превратите свой класс в забавный дом с мировым достоянием. Вы помните шоу Highlander с 1990-х годов? Синглтон подобен этому, потому что: А. Он никогда не умрет; и B. Может быть только один. Так что перестаньте слушать всех этих DI weenies и реализовать свой синглтон с отказом. Вот еще несколько веских причин...

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

Ответ 8

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

Синглтон должен использоваться для только одного экземпляра данного класса. Хранилище шаблонов содержит отличную информацию о Singleton.

Ответ 9

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

Я бы сказал, что singleton следует использовать, если модель домена диктует (а не "предлагает" ), что она есть. Все остальные случаи - это просто accendentally отдельные экземпляры класса.

Ответ 10

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

Мне приходится не соглашаться с Орионом, хотя большую часть времени я видел, что singeltons злоупотребляли не глобальными переменными в одежде, а скорее похожими на глобальные сервисы (методы) в одежде. Интересно отметить, что если вы попытаетесь использовать Singeltons в SQL Server 2005 в безопасном режиме через интерфейс CLR, система отметит код. Проблема в том, что у вас есть постоянные данные за пределами любой транзакции, которая может работать, конечно, если вы сделаете переменную экземпляра только для чтения, вы можете обойти эту проблему.

Эта проблема привела к многому переделке для меня на один год.

Ответ 11

Священные войны! Хорошо, дайте мне посмотреть. В прошлый раз я проверил дизайн полиции сказал..

Синглтоны плохи, потому что они препятствуют автоматическому тестированию - экземпляры не могут быть созданы заново для каждого тестового примера. Вместо этого логика должна быть в классе (A), который может быть легко создан и протестирован. Другой класс (B) должен нести ответственность за ограничение создания. Единый принцип ответственности на первый план! Это должно быть знание команды, которое вы должны пройти через B, чтобы получить доступ к A-типу командного соглашения.

Я согласен в основном.

Ответ 12

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

Существует статический singleton, в котором класс заставляет только один экземпляр класса для каждого процесса (в Java фактически один для ClassLoader). Другой вариант - создать только один экземпляр.

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

Создание только одного экземпляра - это хорошо. Вы просто создаете один экземпляр при запуске программ, а затем передаете указатель на этот экземпляр всем остальным объектам, которые в нем нуждаются. Фреймворки зависимостей делают это проще - вы просто настраиваете область действия объекта, а структура DI будет заботиться о создании экземпляра и передаче его всем, кто в этом нуждается. Например, в Guice вы должны аннотировать класс с помощью @Singleton, а среда DI создаст только один экземпляр класса (для каждого приложения - вы можете иметь несколько приложений, работающих в одной JVM). Это упрощает тестирование, потому что вы можете создать новый экземпляр класса для каждого теста и позволить сборщику мусора уничтожить экземпляр, когда он больше не используется. Глобальное состояние не будет протекать из одного теста в другой.

Для получения дополнительной информации: Чистые коды кодов - "Глобальное состояние и одиночные игры"

Ответ 13

Синглтон как деталь реализации в порядке. Синглтон как интерфейс или механизм доступа - это гигантский PITA.

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

Ответ 14

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

Я должен сказать, что вы на самом деле не описывая Somthing, который должен быть единым объектом и спорно, что любой из них, кроме сериализации данных должны были singelton.

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

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

Ответ 15

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

Во-вторых, люди часто считают, что ленивая инициализация с двойной проверкой блокировки является хорошим способом их реализации.

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

Ответ 16

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

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

Ответ 17

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

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

Ответ 18

Я использовал синглтоны несколько раз в сочетании с Spring и не считал это костылем или ленивым.

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

В моем случае синглтон содержал критерии конфигурации клиента - местоположение файла css, критерии соединения db, набор функций и т.д. - специфичные для этого клиента. Эти классы были созданы и доступны через Spring и совместно используются пользователями с одинаковой конфигурацией (т.е. 2 ​​пользователя из той же компании). * ** Я знаю, что есть имя для этого типа приложения, но оно ускользает от меня *

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

Ответ 19

Я много читаю о "Синглтоне", его проблемах, когда его использовать и т.д., и это мои выводы до сих пор:

  • Путаница между классической реализацией Синглтона и реальным требованием: ТОЛЬКО ОДНА ИНСТАНЦИЯ КЛАССА!

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

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

  • Не TDD. Если вы выполняете TDD, зависимости извлекаются из реализации, потому что вы хотите, чтобы ваши тесты были легкими для записи. Это делает вашу объектную модель лучшей. Если вы используете TDD, вы не будете писать статический GetInstance =). BTW, если вы считаете объекты с четкими обязанностями вместо классов, вы получите тот же эффект =).

Ответ 20

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

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

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

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

Кроме того, это была фиксированная, общесистемная, легко доступная точка для данных компании.

Ответ 21

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

Вместо этого я предлагаю либо спрятать Синглтон за factory. Таким образом, если вам нужно изменить поведение экземпляра службы в будущем, вы можете просто изменить factory, а не все типы, которые потребляют Singleton.

Еще лучше, используйте инверсию контейнера управления! Большинство из них позволяют отделять поведение экземпляров от реализации ваших классов.

Ответ 22

Одна страшная вещь в одиночных играх, например, в Java, заключается в том, что в некоторых случаях вы можете получить несколько экземпляров одного и того же синглтона. JVM уникально идентифицирует на основе двух элементов: полное имя класса и загрузчик классов, ответственных за его загрузку.

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

Ответ 23

Напиши нормальные, проверяемые, инъецируемые объекты, и пусть Guice/ Spring/все обрабатывает экземпляр. Шутки в сторону.

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

Ответ 24

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

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

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

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

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