Что такого плохого в синглетах? [закрыто]

1984

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

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

Пожалуйста, поддержите ваши ответы " фактами, ссылками или конкретными знаниями "

m87
источник
6
Я должен сказать, что использование одноэлементного дизайна недавно обожгло меня, поскольку я пытался адаптировать код. Поскольку я делаю это в свое свободное время, мне почти лень рефакторинг. Плохие новости для производительности.
Марчин
71
В ответах есть много «минусов», но я также хотел бы увидеть несколько хороших примеров того, когда шаблон хорош, чтобы контрастировать с плохим ...
DGM
50
Я написал сообщение в блоге на эту тему несколько месяцев назад: jalf.dk/blog/2010/03/… - и позвольте мне сказать это прямо. Лично я не могу вспомнить ни одной ситуации, когда синглтон является правильным решением. Это не значит, что такой ситуации не существует, но ... называть их редкими - преуменьшение.
Джалф
8
@ AdamSmith это не значит, что вы должны , но это означает, что вы можете получить к нему доступ таким образом. И если вы не собираетесь получать к нему доступ таким образом, то нет особых оснований делать его синглтоном. Таким образом, ваш аргумент заключается в том, что «создание синглтона не повредит, если мы не будем относиться к нему как к синглтону. Да, отлично. Моя машина также не загрязняет окружающую среду, если я в нее не еду. Но тогда легче просто не приобретать машину в первую очередь.;) (полное раскрытие: у меня на самом деле нет машины)
jalf
35
Худшая часть всей этой темы в том, что люди, которые ненавидят синглетонов, редко дают конкретные советы о том, что вместо этого использовать. Например, ссылки на статьи в журналах и самостоятельно публикуемые блоги на протяжении всей этой статьи продолжаются и объясняют, почему не следует использовать синглтоны (и все они являются отличными причинами), но они чрезвычайно малы для замены. Хотя много ручного махания. Те из нас, кто пытается научить новых программистов, почему бы не использовать синглтоны, не имеют много хороших сторонних контрпримеров, на которые можно указать, только надуманные примеры. Это утомительно.
Ti Strga

Ответы:

1294

Перефразированный от Брайана Баттона:

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

  2. Они нарушают принцип единственной ответственности : в силу того, что они контролируют свое собственное творение и жизненный цикл.

  3. Они по своей сути заставляют код быть тесно связанным . Это во многих случаях затрудняет их тестирование.

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

Джим Бургер
источник
324
Я не согласен с вами. Поскольку комментарии разрешены только 600 символов, я написал блог, чтобы прокомментировать это, пожалуйста, смотрите ссылку ниже. jorudolph.wordpress.com/2009/11/22/singleton-considerations
Йоханнес Рудольф
61
Что касается пунктов 1 и 4, я думаю, что синглтоны полезны и фактически идеально подходят для кэширования данных (особенно из БД). Увеличение производительности значительно превосходит сложности, связанные с моделированием юнит-тестов.
Дай Бок
56
@Dai Bok: «кеширование данных (особенно из БД)» использует шаблон прокси, чтобы сделать это ...
paxos1977
55
Вау, отличные отзывы. Я, вероятно, использовал здесь слишком агрессивную формулировку, поэтому имейте в виду, что я отвечал на вопрос с отрицательной направленностью. Предполагалось, что мой ответ будет кратким списком «анти-паттернов», возникающих при плохом использовании Синглтона. Полное раскрытие; Я тоже время от времени пользуюсь Singletons. Есть более нейтрально поставленные вопросы о SO, которые могли бы стать отличным форумом, когда Singletons можно считать хорошей идеей. Например, stackoverflow.com/questions/228164/…
Джим Бургер
21
Они не так хороши для кэширования в многопоточной среде. Вы можете легко победить кеш с несколькими потоками, борющимися за ограниченный ресурс. [поддерживается синглтоном]
монахи
449

Синглтоны решают одну (и только одну) проблему.

Ресурс Спор.

Если у вас есть какой-то ресурс, который

( 1 ) может иметь только один экземпляр, и

( 2 ) вам нужно управлять этим единственным экземпляром,

Вам нужен синглтон .

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

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

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

S.Lott
источник
43
Аппаратное обеспечение также является примером, верно? Встраиваемые системы имеют много оборудования, которое может использовать синглтоны - или, может быть, одно большое? <ухмылка>
Джефф
170
Полностью согласен. Существует много решительных разговоров «эта практика плохая», которые не имеют никакого представления о том, что практика может иметь свое место. Часто, практика только "плоха", потому что она часто используется неправильно. В паттерне Синглтона нет ничего плохого, если он применяется соответствующим образом.
Дамовиза
53
Реальные синглтоны по принципу встречаются очень редко (и очередь на принтер, конечно же, не одна, и не является файлом журнала - см. Log4j). Чаще всего аппаратное обеспечение является единичным по совпадению, а не по принципу. Все оборудование, подключенное к ПК, в лучшем случае является случайным (например, несколько мониторов, мышей, принтеров, звуковых карт). Даже детектор частиц стоимостью 500 млн. Долларов является единичным по совпадению и бюджетным ограничениям, которые не применяются в программном обеспечении, то есть: нет единого. В телекоммуникациях ни номер телефона, ни физический телефон не являются одиночными (например, ISDN, колл-центр).
digitalarbeiter
23
Аппаратное обеспечение может иметь только один экземпляр множества ресурсов, но аппаратное обеспечение не является программным. Нет причин, по которым один последовательный порт на плате разработки должен быть смоделирован как Singleton. Действительно, его моделирование только усложнит портирование на новую плату с двумя портами!
dash-tom-bang
19
Таким образом, вы бы написали два одинаковых класса, дублируя много кода, просто чтобы у вас было два синглета, представляющих два порта? Как насчет использования двух глобальных объектов SerialPort? Как насчет того, чтобы вообще не моделировать аппаратное обеспечение как классы? И почему вы используете синглтоны, которые также подразумевают глобальный доступ? Хотите ли вы, чтобы каждая функция в вашем коде имела доступ к последовательному порту?
Джалф
352

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

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

Фил Райт
источник
17
Ошибка, которую я вижу в Синглтоне, состоит в том, что люди используют их вместо глобальных, потому что они как-то «лучше». Проблема состоит в том (как я это вижу), что то, что Синглтон приносит на стол в этих случаях, не имеет значения. (Например, Construct-on-first-use легко реализовать в не-синглтоне, даже если он не использует конструктор для этого.)
dash-tom-bang
21
Причина, по которой мы смотрим на них свысока, заключается в том, что мы часто видим, что они используются неправильно и слишком часто. «Мы» знаем, что у них есть причина.
Бьярке Фрейнд-Хансен
5
@Phil, Вы заявили, что «время от времени вы можете находить, что это идеальное решение, и поэтому используйте его». Хорошо, так в каком случае мы бы нашли синглтон полезным?
Pacerier
22
@Pacerier, когда выполняются все следующие условия: (1) вам нужно только одно из чего-либо, (2) вам нужно передать эту вещь в качестве аргумента при большом количестве вызовов методов, (3) вы готовы принять возможность когда-нибудь провести рефакторинг в обмен на немедленное уменьшение размера и сложности вашего кода, не пропуская всюду проклятую вещь.
Антином
18
Я не чувствую, что это что-то отвечает, а просто говорит, что «иногда это может подходить, а иногда нет». Хорошо, но почему и когда? Что делает этот ответ больше, чем аргумент в пользу модерации ?
Гильденстерн
219

Misko Hevery, от Google, имеет несколько интересных статей именно на эту тему ...

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

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

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

Джейсон
источник
8
Статьи Миско на эту тему - лучшая вещь на данный момент.
Крис Майер
22
Первая ссылка на самом деле не решает проблему с синглетами, а предполагает статическую зависимость внутри класса. Можно исправить данный пример, передав параметры, но по-прежнему использовать синглтоны.
DGM
17
@DGM: Точно - на самом деле, существует огромная логическая несоответствие между частью статьи «обоснование» и частью «Синглтоны - причина».
Харпер Шелби
1
Статья Миско о CreditCard - крайний пример неправильного использования этого паттерна.
Алекс
2
Читая вторую статью, Singletons фактически являются частью описанной объектной модели. Однако, вместо того, чтобы быть доступными глобально, они являются частными для объектов Factory.
FruitBreak,
121

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

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

Cem Catikkas
источник
20
Что это за экземпляр, доступный во всем приложении? Ой. Глобальный . «Синглтон - это не шаблон для переноса глобалов» - это либо наивно, либо вводит в заблуждение, так как по определению шаблон оборачивает класс вокруг глобального экземпляра.
Чао
26
Конечно, вы можете создавать один экземпляр класса при запуске приложения и вставлять этот экземпляр через интерфейс во все, что его использует. Реализация не должна заботиться о том, что может быть только один.
Скотт Уитлок
4
@Dainius: Там действительно нет, в конце концов. Конечно, вы не можете произвольно заменить экземпляр другим. (За исключением тех порождающих лицевые моменты, когда вы это делаете . Я на самом деле уже видел setInstanceметоды раньше.) Однако это вряд ли имеет значение - та слабость, которая «нуждалась» в синглтоне, также не знала о том, что такое инкапсуляция или что с ней не так. изменяемое глобальное состояние, поэтому он услужливо (?) предоставил сеттеры для каждого. Один. поле. (И да, это случается. Многое . Почти каждый синглтон, который я когда-либо видел в дикой природе, был изменчивым по
своему
4
@Dainius: в значительной степени у нас уже есть. «Предпочитаю композицию наследованию» уже давно. Когда наследование является явно лучшим решением, вы, конечно, можете его использовать. То же самое с синглетами, глобалами, потоками gotoи т. Д. Они могут работать во многих случаях, но, честно говоря, «работает» недостаточно - если вы хотите пойти против общепринятого мнения, вам лучше продемонстрировать, как ваш подход является лучше , чем обычные растворы. И я еще не видел такой случай для шаблона Singleton.
Чао
3
Чтобы мы не говорили мимо друг друга, я говорю не только о глобально доступном экземпляре. Есть много случаев для этого. То, о чем я говорю (особенно когда я говорю «синглтон-заглавные буквы»), - это шаблон синглтона GoF, который встраивает этот единственный глобальный экземпляр в сам класс, предоставляет его через getInstanceметод с аналогичным именем или предотвращает существование второй экземпляр. Честно говоря, на тот момент, вы могли бы даже не иметь один экземпляр.
Цао
72

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

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

Итак, в основном:

public MyConstructor(Singleton singleton) {
    this.singleton = singleton;
}

скорее, чем:

public MyConstructor() {
    this.singleton = Singleton.getInstance();
}

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

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

Майк Стоун
источник
17
Хе-хе, если вы делаете это везде, то вам также придется везде передавать ссылку на сингелтон, и, таким образом, у вас больше нет синглтона. :) (что, как правило, хорошо для ИМО.)
Бьярке Фрейнд-Хансен
2
@ BjarkeFreund-Hansen - Чепуха, о чем ты говоришь? Синглтон - это просто экземпляр класса, который был создан один раз. Ссылка на такой Singleton не копирует реальный объект, он просто ссылается на него - у вас все еще есть тот же объект (читай: Singleton).
М. Мимпен
2
@ M.Mimpen: Нет, синглтон с заглавной буквы (который обсуждается здесь) является экземпляром класса, который (а) гарантирует, что когда-либо будет существовать только один экземпляр, и (б) доступ к нему осуществляется через собственный класс. встроенная глобальная точка доступа. Если вы заявили, что ничего не должно звонить getInstance(), то (б) уже не совсем верно.
Чао
2
@cHao Я не слежу за тобой, или ты не понимаешь, кому я комментирую - это Бьярке Фрейнд-Хансен. Бьярке утверждает, что наличие нескольких ссылок на синглтон приводит к нескольким синглетонам. Это, конечно, неправда, так как нет глубоких копий.
М. Мимпен
6
@ M.Mimpen: я беру его комментарий, чтобы больше ссылаться на семантический эффект. После того, как вы объявили вне закона призывы getInstance(), вы фактически отбросили одно полезное различие между шаблоном Singleton и обычной ссылкой. Что касается остальной части кода, единственность больше не является свойством. Только вызывающий абонент getInstance()должен знать или даже заботиться о том, сколько их существует. С одним только вызывающим абонентом для класса требуется больше усилий и гибкости для надежного обеспечения единственности, чем для того, чтобы вызывающий просто сохранял ссылку и использовал ее повторно.
Чао
69

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

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

В сборки мусора синглтоны могут быстро стать проблемой в отношении управления памятью.

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

Кимоз
источник
4
я знаю, что это многолетняя нить. привет @ Kimoz ты сказал: - одиночные игры могут быстро стать проблемой в отношении управления памятью. Я хотел бы более подробно объяснить, какие проблемы могут возникнуть при сборке мусора.
Томас
@Kimoz, вопрос в том, почему шаблон синглтона сам по себе не является проблемой? и вы просто повторили эту мысль, но не предоставили ни одного действительного варианта использования шаблона синглтона.
Pacerier
@Thomas, потому что синглтон по определению существует только в одном экземпляре. Таким образом, часто сложно присвоить единственную ссылку нулю. Это можно сделать, но это означает, что вы полностью контролируете точку, после которой синглтон не используется в вашем приложении. И это редко, и, как правило, совершенно противоположно тому, что ищут одиночные энтузиасты: простой способ сделать один экземпляр всегда доступным. На некоторых DI-фреймворках, таких как Guice или Dagger, невозможно избавиться от синглтона, и он навсегда останется в памяти. (Хотя синглтоны в контейнерах намного лучше, чем домашние).
Сниколас
54

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

Peter Mortensen
источник
9
Это больше похоже на проблему с модульным тестированием, которое может тестировать объекты (блоки), функции (блоки), целые библиотеки (блоки), но не работать с чем-либо статичным в классе (также с модулями).
v010dya
2
в любом случае, вы не предполагаете использовать все внешние ссылки? Если да, то в чем проблема для moc singleton, если нет, действительно ли вы проводите модульное тестирование?
Дайний,
@Dainius: издеваться над экземплярами гораздо меньше проблем, чем насмехаться над классами. Вы могли бы предположительно извлечь тестируемый класс из остальной части приложения и протестировать с поддельным Singletonклассом. Однако это значительно усложняет процесс тестирования. Например, теперь вам нужно иметь возможность выгружать классы по своему усмотрению (на самом деле это не так для большинства языков) или запускать новую ВМ для каждого теста (читай: тестирование может занять тысячи раз дольше). Однако для двоих зависимость от Singleton- это деталь реализации, которая теперь просачивается во все ваши тесты.
Цао
Powermock может издеваться над статичными вещами.
Сниколас
означает ли насмешка над объектом создание реального объекта? Если насмешка не создает реального объекта, то почему имеет значение, является ли класс одноэлементным или метод является статическим?
Арун Радж
45

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

Рассмотрим следующую ситуацию: Как разработчик, вы должны создать веб-приложение, которое обращается к базе данных. Чтобы параллельные вызовы базы данных не конфликтовали друг с другом, вы создаете сохранение потока SingletonDao:

public class SingletonDao {
    // songleton's static variable and getInstance() method etc. omitted
    public void writeXYZ(...){
        synchronized(...){
            // some database writing operations...
        }
    }
}

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

Пока все хорошо.

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

Много синглетонов

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

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

UOOO
источник
4
если вы не знаете, как реализовать синглтон, вы не должны этого делать. Если вы не знаете, что делаете, вы должны сначала найти это, и только после этого делать то, что вам нужно.
Дайний,
3
Это интересно, у меня есть вопрос. Так в чем же проблема, если синглтоны - каждый на другой машине / JVM - подключаются к одной базе данных? Область применения синглетонов предназначена только для этой конкретной JVM, и это все еще верно даже в кластере. Вместо того, чтобы просто философски говорить, что эта конкретная ситуация плоха, потому что наше намерение было единым объектом в приложении, я был бы рад увидеть любые технические проблемы, которые могут возникнуть из-за этой договоренности.
Саураб Патил
39
  1. Он легко (ab) используется как глобальная переменная.
  2. Классы, которые зависят от синглетонов, относительно сложнее для модульного тестирования в изоляции.
jop
источник
33

Монополия - это дьявол, а синглтоны с нечитаемым / изменяемым состоянием - это «настоящая» проблема ...

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

Глобальный это плохо, потому что:

  • а. Это вызывает конфликт пространства имен
  • б. Это подвергает государство необоснованному

Когда дело доходит до синглетонов

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

В последнем утверждении он ссылается на концепцию блога «одиночки - лжецы».

Как это относится к монополии?

Чтобы начать игру в монополию, сначала:

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

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

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

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

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

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

Как это относится к программированию?

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

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

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

Evan Plaice
источник
1
Что если синглтон обналичивает некоторые данные?
Йола
@Yola Это уменьшило бы количество записей, если синглтон был запланирован для обновления по заранее определенному и / или фиксированному расписанию, таким образом уменьшая конфликт потока. Тем не менее, вы не сможете точно протестировать любой код, взаимодействующий с одноэлементным, если вы не смоделируете не-одноэлементный экземпляр, который имитирует такое же использование. Люди TDD, вероятно, подойдут, но это будет работать.
Эван Плейс
@EvanPlaice: Даже с пародией у вас могут возникнуть проблемы с кодом, который говорит Singleton.getInstance(). Язык, поддерживающий отражение, может обойти это, установив поле, в котором хранится One True Instance. IMO, тем не менее, тесты становятся немного менее заслуживающими доверия, когда вы начинаете заниматься с личным состоянием другого класса.
Чао
28

Синглтон не о единственном экземпляре!

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

  • Проблема : Singleton может быть проблемой в многопоточной среде
    Решение : Используйте однопоточный процесс начальной загрузки для инициализации всех зависимостей вашего singleton.
  • Проблема : трудно издеваться над одиночками.
    Решение : использовать метод Factory pattern для издевательства

Вы можете отобразить MyModelна TestMyModelкласс , который наследует это, везде , когда MyModelбудет закачиваться вы получите TestMyModelinstread. - Проблема : синглтоны могут вызвать утечку памяти, поскольку они никогда не утилизируются.
Решение : Ну, избавьтесь от них! Внедрите в свое приложение функцию обратного вызова для правильной утилизации синглетонов, вы должны удалить все связанные с ними данные и, наконец, удалить их из Factory.

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

  • Singletons улучшает читабельность : вы можете посмотреть на ваш класс и увидеть, какой синглтон он внедрил, чтобы выяснить, каковы его зависимости.
  • Singletons улучшает обслуживание : после того, как вы удалили зависимость из класса, вы только что удалили однокомпонентную инъекцию, вам не нужно переходить и редактировать большую ссылку других классов, которые просто перемещали вашу зависимость (Это вонючий код для меня @Jim Burger )
  • Singletons улучшает память и производительность : когда что-то происходит в вашем приложении, и для доставки требуется длинная цепочка обратных вызовов, вы тратите впустую память и производительность, с помощью Singleton вы сокращаете средний уровень и улучшаете свою производительность и использование памяти ( избегая ненужных локальных переменных размещения).
Илья Газман
источник
2
Это не решает мою главную проблему с Singletons, которая заключается в том, что они разрешают доступ к глобальному состоянию из любого из тысяч классов в вашем проекте.
LegendLength
8
Это было бы целью ...
Илья Газман
LegendLength Почему это не так? Например, в моем приложении у меня есть одноэлементный Settingsобъект, который доступен из любого виджета, так что каждый виджет знает, как форматировать отображаемые числа. Если бы это был не глобально доступный объект, я должен был бы вставить его в конструктор в каждый виджет в конструкторе и сохранить ссылку на него как переменную-член. Это ужасная трата памяти и времени.
ВК
23

Мой ответ о том, как синглтоны плохие, всегда звучит так: «Их трудно сделать правильно». Многие из основополагающих компонентов языков являются синглетонами (классы, функции, пространства имен и даже операторы), как и компоненты в других аспектах вычислений (локальный хост, маршрут по умолчанию, виртуальная файловая система и т. Д.), И это не случайно. Хотя они время от времени доставляют неприятности и разочарование, они также могут заставить многое работать намного лучше.

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

Все говорят о Синглтоне как о глобале, потому что они в основном так и есть. Тем не менее, большая (к сожалению, не вся) вредность в глобальном масштабе проистекает не из того, что он глобальный, а из-за его использования. То же самое касается синглетонов. На самом деле тем более, что «отдельный экземпляр» на самом деле не должен означать «глобально доступный». Это более естественный побочный продукт, и, учитывая все плохое, что мы знаем, оно исходит от нас, мы не должны спешить использовать глобальную доступность. Как только программисты видят Singleton, они, кажется, всегда получают к нему доступ напрямую через метод его экземпляра. Вместо этого вы должны перейти к нему так же, как к любому другому объекту. Большая часть кода даже не должна знать, что имеет дело с синглтоном (слабая связь, верно?). Если только небольшой кусочек кода обращается к объекту, как к глобальному объекту, большой вред отменяется.

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

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

Если вы избежите этих ошибок, Singletons все еще могут быть PITA, но они готовы увидеть, что многие худшие проблемы значительно смягчены. Представьте себе Java Singleton, который явно определяется как один раз для загрузчика классов (что означает, что ему нужна политика безопасности потоков), с определенными методами создания и уничтожения и жизненным циклом, который определяет, когда и как они будут вызваны, и чей метод «instance» имеет защита пакета, так что к нему обычно обращаются через другие, не глобальные объекты. Все еще потенциальный источник проблем, но, конечно, гораздо меньше проблем.

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

Кристофер Смит
источник
23

Смотрите Википедию Singleton_pattern

Некоторые люди считают, что он также является анти-паттерном, который использует его чрезмерно, вводя ненужные ограничения в ситуациях, когда единственного экземпляра класса фактически не требуется. [1] [2] [3] [4]

Список литературы (только соответствующие ссылки из статьи)

  1. ^ Алекс Миллер. Образцы, которые я ненавижу № 1: Синглтон , июль 2007
  2. ^ Скотт Денсмор. Почему синглтоны злые , май 2004
  3. ^ Стив Йегге. Синглтоны считаются глупыми , сентябрь 2004
  4. ^ JB Рейнсбергер, IBM. Используй свои синглеты с умом , июль 2001
GUI Junkie
источник
8
Описание модели не объясняет, почему она считается злой ...
Jrgns
2
Вряд ли справедливо: «Некоторые люди считают, что он также является анти-паттерном, который считает, что он чрезмерно используется, вводя ненужные ограничения в ситуациях, когда единственный экземпляр класса фактически не требуется». Посмотрите на ссылки ... В любом случае для меня есть RTFM.
GUI Junkie
17

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

Использование одного экземпляра класса является допустимой конструкцией, если в коде применяются следующие средства:

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

  2. Убедитесь, что Singleton является поточно-ориентированным. Это дано.

  3. Синглтон должен быть простым по природе и не слишком сложным.

  4. Во время выполнения вашего приложения, где синглтоны должны быть переданы данному объекту, используйте фабрику классов, которая создает этот объект и заставляет фабрику классов передавать экземпляр singleton классу, который в этом нуждается.

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

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

user1578119
источник
+1, наконец , ответ, который адресован, когда синглтон может быть действительным.
Pacerier
16

Я хотел бы рассмотреть 4 пункта в принятом ответе, надеюсь, кто-то может объяснить, почему я не прав.

  1. Почему плохо скрывать зависимости в вашем коде? Уже есть десятки скрытых зависимостей (вызовы времени выполнения C, вызовы API OS, вызовы глобальных функций), и одноэлементные зависимости легко найти (поиск instance ()).

    «Создание чего-то глобального, чтобы избежать его распространения, - это запах кода». Почему бы не передать что-то, чтобы не сделать это одним запахом кода?

    Если вы пропускаете объект через 10 функций в стеке вызовов просто для того, чтобы избежать одиночного вызова, это так здорово?

  2. Принцип единой ответственности: я думаю, что это немного расплывчато и зависит от вашего определения ответственности. Уместным будет вопрос, почему добавление этой конкретной «ответственности» к классу имеет значение?

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

  4. Почему это меняет то, как долго длится государство? Синглтоны могут быть созданы или уничтожены вручную, так что элемент управления все еще там, и вы можете сделать время жизни таким же, как было бы время жизни не-одиночного объекта.

Относительно юнит-тестов:

  • не все классы должны быть проверены модулем
  • не все классы, которые должны быть проверены модулем, должны изменить реализацию синглтона
  • если они делают нужно быть протестировано и сделать необходимость изменить реализацию, это легко изменить класс с помощью синглтона к иметь одноплодной переданную ей через инъекцию зависимостей.
Джон
источник
1
1. Все эти скрытые зависимости? Это тоже плохо. Скрытые зависимости всегда зло. Но в случае с CRT и OS они уже есть, и это единственный способ что-то сделать. (Попробуйте написать программу на C без использования среды выполнения или ОС.) Эта способность делать что-то значительно перевешивает их недостатки. Синглтоны в нашем коде не дают такой роскоши; так как они находятся в нашей сфере контроля и ответственности, каждое использование (читай: каждая дополнительная скрытая зависимость) должно быть оправдано как единственный разумный способ сделать что-то. Очень, очень немногие из них на самом деле.
Чао
2. «Ответственность» обычно определяется как «причина для изменения». Синглтон заканчивает тем, что управляет своей жизнью и выполняет свою реальную работу. Если вы измените способ выполнения работы или построение графа объектов, вам придется изменить класс. Но если у вас есть другой код, строящий граф объектов, и ваш класс просто выполняет свою реальную работу, этот код инициализации может настроить граф объектов так, как ему нравится. Все гораздо более модульно и тестируемо, потому что вы можете вставлять тестовые дубликаты и разбирать все по своему желанию, и вы больше не полагаетесь на скрытые движущиеся части.
Чао
1
@cHao: 1. Хорошо, что вы понимаете, что «способность делать вещи значительно перевешивает их недостатки». Примером может служить структура ведения журнала. Плохо поручать передачу глобального объекта регистрации посредством внедрения зависимостей через слои вызовов функций, если это означает, что разработчики не поощряются к ведению журнала. Следовательно, синглтон. 3. Ваша точка жесткой связи важна только в том случае, если вы хотите, чтобы клиенты этого класса контролировали поведение с помощью полиморфизма. Это часто не тот случай.
Джон
2
4. Я не уверен, что «нельзя уничтожить вручную» является логическим следствием «может быть только один экземпляр». Если вы так определяете синглтон, то мы не говорим об одном и том же. Все классы не должны подвергаться модульному тестированию. Это бизнес-решение, и иногда время выхода на рынок или стоимость разработки имеют приоритет.
Джон
1
3. Если вам не нужен полиморфизм, вам даже не нужен экземпляр. С тем же успехом вы можете сделать его статическим классом, потому что в любом случае вы привязываете себя к одному объекту и одной реализации - и, по крайней мере, тогда API вам не обманывает.
cHao
15

У Винса Хьюстона есть следующие критерии, которые кажутся мне разумными:

Синглтон следует рассматривать только в том случае, если выполнены все три из следующих критериев:

  • Право собственности на один экземпляр не может быть назначено разумно
  • Ленивая инициализация желательна
  • Глобальный доступ не предусмотрен для

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

JS.
источник
14

Синглтоны плохие с пуристической точки зрения.

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

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

Синглтоны иногда также усложняют юнит-тестирование .

tacone
источник
3
Мой опыт показывает, что , начиная с одиночек действительно повредит вам , даже в краткосрочной перспективе, не считая долгосрочной перспективе. Этот эффект может быть менее заметен, если приложение уже существует в течение некоторого времени и, вероятно, уже заражено другими синглетонами. Начиная с нуля? Избегайте их любой ценой! Хотите один экземпляр объекта? Позвольте фабрике управлять созданием этого объекта.
Свен
1
AFAIK Singleton - это заводской метод. Таким образом, я не получаю ваши рекомендации.
Таконе
3
«Фабрика»! = «Фабрика_метод, которая не может быть отделена от других полезных вещей в том же классе»
Свен
13

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

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

Бен Хоффштейн
источник
6
Я думаю, что обратная реакция больше связана с людьми, практикующими формализованное модульное тестирование, понимая, что с ними приходится иметь дело с кошмаром.
Джим Бургер
1
Не уверен, почему это в -1. Это не самый описательный ответ, но он также не ошибается.
Программист вне закона
13

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

Peter Mortensen
источник
3
по умолчанию не являются бобами Spring, Singletons?
стройное
3
Да, но я имею в виду «кодирование» синглетонов. Я не «написал синглтон» (то есть с частным конструктором yada yada yada согласно шаблону проектирования) - но да, с пружиной я использую один экземпляр.
prule
4
поэтому, когда другие делают это, это нормально (если я буду использовать это после), но если другие сделают это, и я не буду использовать это, это зло?
Дайний,
11

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

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

Loki Astari
источник
1
Спасибо Локи :) Именно моя точка зрения. Вся охота на ведьм напоминает мне о дебатах Гото. Инструменты для людей, которые знают, как их использовать; использование инструмента, который вам не нравится, может быть опасным для вас, поэтому избегайте его, но не говорите другим не использовать / не учиться использовать его должным образом. Я не совсем "про-синглтон", но мне нравится тот факт, что у меня есть такой инструмент, и я чувствую, где его целесообразно использовать. Период.
dkellner
8

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

Синглтоны затрудняют переход от них к обычным объектам.

Кроме того, слишком просто написать не-поточно-безопасный синглтон.

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

void some_class::some_function(parameters, service_provider& srv)
{
    srv.get<error_logger>().log("Hi there!");
    this->another_function(some_other_parameters, srv);
}
Роман Одайский
источник
4
Передаваемый аргумент для каждого метода блестящий, он должен найти хотя бы 10 лучших способов загрязнения вашего API.
Дайний,
Это очевидный недостаток, и тот, который должен был быть обработан языком, посредством аргументов, которые каким-то образом распространяются на вложенные вызовы, но при отсутствии такой поддержки, это должно быть сделано вручную. Учтите, что даже природные синглтоны, такие как объект, представляющий системные часы, могут создавать проблемы. Например, как вы собираетесь покрывать зависящий от часов код (например, многотарифный счетчик электроэнергии) тестами?
Роман Одайский
зависит от того, что вы тестируете, если вы не тестируете синглтон, почему вы заботитесь о том, как он себя ведет, если ваш 2 удаленный объект зависит от поведения друг друга, это не проблема синглтона ..
Дайниус,
Не могли бы вы предоставить, какой язык будет распространяться на вложенные вызовы?
Дайний,
1
Если у вас есть один модуль, который зависит от другого, и вы не знаете / не можете его перемещать, вам будет трудно, независимо от того, синглтон он или нет. Люди часто используют наследование, где они должны использовать композицию, но вы не говорите, что наследование плохое, и ООП следует избегать любой ценой, потому что так много людей делают ошибки проектирования, или вы?
Дайний,
8

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

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

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

Mark Lindell
источник
8

Недавняя статья на эту тему Криса Рита в « Кодировании без комментариев» .

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

http://geekswithblogs.net/AngelEyes/archive/2013/09/08/singleton-i-love-you-but-youre-bringing-me-down-re-uploaded.aspx

stephenbayer
источник
7

Синглтоны НЕ плохие. Это плохо, когда вы делаете что-то глобально уникальное, а не уникальное.

Однако существуют «службы области приложения» (подумайте о системе обмена сообщениями, которая обеспечивает взаимодействие компонентов) - это CALLS для одиночного объекта, «MessageQueue» - класс, имеющий метод «SendMessage (...)».

Затем вы можете сделать следующее со всего места:

MessageQueue.Current.SendMessage (new MailArrivedMessage (...));

И, конечно же, сделать:

MessageQueue.Current.RegisterReceiver (это);

в классах, которые реализуют IMessageReceiver.

StormianRootSolver
источник
6
И если я хочу создать вторую очередь сообщений с меньшей областью действия, почему мне нельзя разрешить повторно использовать ваш код для его создания? Синглтон предотвращает это. Но если бы вы просто создали обычный класс очереди сообщений, а затем создали один глобальный экземпляр, который будет действовать как «область приложения», я мог бы создать второй экземпляр для другого использования. Но если вы сделаете класс одиночным, мне придется написать второй класс очереди сообщений.
2010 года
1
Кроме того, почему мы не должны просто иметь глобальный CustomerOrderList, чтобы мы могли красиво вызывать его из любого места, например MessageQueue? Я полагаю, что ответ одинаков для обоих: это фактически создание глобальной переменной.
LegendLength
7

Слишком много людей помещают объекты, которые не являются потокобезопасными, в шаблон синглтона. Я видел примеры DataContext ( LINQ to SQL ), выполненного в одноэлементном шаблоне, несмотря на тот факт, что DataContext не является потокобезопасным и является чисто единичным объектом.

Peter Mortensen
источник
многие пишут небезопасный многопоточный код, означает ли это, что мы должны исключать потоки?
Дайний,
@Dainius: На самом деле, да. IMO модель параллелизма по умолчанию должна быть многопроцессорной, чтобы два процесса могли (1) легко передавать сообщения друг другу и / или (2) совместно использовать память по мере необходимости. Потоки полезны, если вы хотите поделиться всем , но вы никогда этого не хотите. Его можно эмулировать, разделяя все адресное пространство, но это также будет считаться анти-паттерном.
Чао
@Dainius: И конечно, это предполагает, что параллелизм честности к добру нужен вообще. Часто все, что вам нужно, - это делать что-то одно, пока вы ждете, пока ОС сделает что-то другое. (Обновление пользовательского интерфейса при чтении из сокета, например.) Приличный асинхронный API может сделать ненужную многопоточность в огромном большинстве случаев.
Чао
поэтому, если у вас есть огромная матрица данных, которую вам нужно обработать, лучше сделать это в одном потоке, потому что многие люди могут сделать это неправильно ..
Дайниус
@Dainius: во многих случаях да. (Потоки могут на самом деле замедлить вас , если вы добавите синхронизацию к миксу. Это яркий пример того, почему многопоточность не должна быть первой мыслью большинства людей.) В других случаях было бы лучше иметь два процесса, которые совместно используют только необходимые вещи. Конечно, вам нужно организовать процессы для совместного использования памяти. Но, честно говоря, я считаю, что это хорошая вещь - по крайней мере, намного лучше, чем режим по умолчанию для всех. Это требует от вас явного указания (и в идеале, чтобы знать), какие части являются общими и, следовательно, какие части должны быть поточно-ориентированными.
Чао
6

Вот еще одна вещь о синглетах, о которой еще никто не говорил.

В большинстве случаев «синглтонность» - это деталь реализации некоторого класса, а не характеристика его интерфейса. Обращение Контейнер Контроля может скрыть эту характеристику от пользователей класса; вам просто нужно пометить ваш класс как одиночный (например, с @Singletonаннотацией в Java) и все; IoCC сделает все остальное. Вам не нужно предоставлять глобальный доступ к вашему экземпляру синглтона, потому что доступ уже управляется IoCC. Таким образом, в IoC Singletons нет ничего плохого.

Предполагается, что GoF Singletons в отличие от IoC Singletons предоставляют «единство» в интерфейсе с помощью метода getInstance (), и поэтому они страдают от всего, что сказано выше.

Владимир Фролов
источник
3
По моему мнению, "singletonity" - это деталь среды выполнения, и ее не следует учитывать программисту, написавшему код класса. Скорее, это должно быть сделано классом USER. только пользователь знает, сколько экземпляров фактически требуется.
Земной двигатель
5

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

Sriram
источник
Потрясающие! Полностью согласен! Но вы могли бы и, возможно, должны разработать гораздо больше. Например, раскрытие того, какие шаблоны проектирования чаще всего игнорируются и как «правильно и минимально» использовать синглтоны. Легче сказать, чем сделать ! : P
cregox
По сути, альтернативой является передача объектов через параметры метода, а не доступ к ним через глобальное состояние.
LegendLength
5

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

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

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

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

мП.
источник
4

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

Ycros
источник
Если ваш класс не ограничен одним экземпляром, вам понадобятся статические члены в вашем классе, управляемые семафорами, что почти одинаково! Какова ваша предложенная альтернатива?
Jeach
У меня есть огромное приложение с «MainScreen», этот экран открывает множество небольших модальных / немодальных окон / UI форм. ИМХО Я чувствую, что MainScreen должен быть одноэлементным, так что, например, виджет где-то в дальнем углу приложения хочет показать свой статус в строке состояния MainScreen, все, что ему нужно сделать, - это MainScreen.getInstance (). SetStatus ( «Немного текста»); Что вы предлагаете в качестве альтернативы? Передать MainScreen по всему приложению ?? : D
Сальвин Фрэнсис
2
@SalvinFrancis: Я бы порекомендовал вам перестать иметь объекты, которые заботятся о вещах, которые им не нужны, и пробираться по приложению, чтобы возиться друг с другом. :) Ваш пример был бы намного лучше сделан с событиями. Когда вы делаете события правильно, виджету даже не нужно заботиться о том, есть ли вообще MainScreen; он просто передает «эй, что-то произошло», и все , кто подписался на событие «что-то произошло» (будь то MainScreen, WidgetTest или что-то еще!), решает, как он хочет ответить. Вот как ООП должно быть сделано в любом случае. :)
cHao
1
@Salvin Подумайте, насколько сложно рассуждать о MainScreen при отладке, если он «молча» обновляется многими компонентами. Ваш пример - отличная причина, почему одиночные игры плохие.
LegendLength