LINUX.ORG.RU

синглтоны это зло?


0

2

В последнее время часто вижу движуху на тему «синглтоны зло». Однако при попытке разобраться в вопросе натыкаешься на каких-то диванных теоретиков которые по существу сказать не могут. Из того что я понял есть три проблемы:

1) типа синглотон нельзя унаследовать. Я принимаю это. Но dependency injection (или как это) или враппер никто не отменял.

2) mocking невозможен. Имхо, не невозможен а затруднён. Опять-таки со своим кодом это не проблема. Проблема если синглтон откуда-то экспортируется. В общем, да, есть трудности, а кому щас легко? Давайте теперь всё сносить что трудно отладить. Впрочем, у меня синглтоны простые и в 99% служат защитой того что нигде в коде, скажем, не появится второй обработчик сетевых соединений итп. Т.е. наоборот спасает от глюков.

3) ну и всякая лабуда в духе «а вот жабе можно вот так извернуть что ...». Короче, жавапроблемы.

4) «Я удалил все синглтоны и мои волосы стали длинными и шелковистыми». И такое я вижу в качестве «аргумента».

Моя точка зрения синглтоны это часть нашей жизни. В питоне, например, модуль это синглтон. Да что там, даже обычная shared-либу можно обозвать синглтоном. Да и вообще у нас есть только одни stdin, stderr и stdout. Никто же не орёт что это несправедливо? Лепить их где попало не стоит, но так это и ежу понятно.

Что скажешь, лор?

Не люблю кастовать, но не могу удержаться.

Cast tailgunner, baverman, , mv, anonymous,

★★★★★

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

true_admin ★★★★★
() автор топика
Ответ на: комментарий от true_admin

ну почему, нормальный паттерн такой

class Foo : public Singleton<Foo> { /* blah */  };
shty ★★★★★
()

А чё сказать-то? Ну поздравляю, ты адекватен =)

Думать надо головой, а не «макакить» готовые паттерны. Любой подход хорош там где он уместен и помогает жить.

ssvda
()

диванные теоретики на то и диванные теоретики...

alex_custov ★★★★★
()

Однако при попытке разобраться в вопросе натыкаешься на каких-то диванных теоретиков которые по существу сказать не могут.

Про аналитиков ты в точку. Пользую сабж по мере надобности, никаких проблем не испытываю. Может потому что не придумываю сложностей там где их нет?!

erfea ★★★★★
()

Кстати, последние тенденции это использовать borg-паттерн. Т.е. когда объекты имеют синхронизированное состояние. Имхо, это совсем не то. Во-первых, может быть race condition. Во-вторых, примитивов синхронизации и так хватает (локи, очереди, ивенты...), зачем городить непонятный огород?

Ну а народ везде проблемы найдёт, хоть с синглтоном, хоть с этим боргом: http://stackoverflow.com/questions/747793/python-borg-pattern-problem

true_admin ★★★★★
() автор топика

синглтоны это зло?

разумеется.

В питоне

питон вообще говно

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

JFreeM ★★★☆
()

Используя DI синглтон становится автоматически не нужен.

А так ничего против не имею.

gatsu
()

синглтоны зло

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

Dantix ★★
()

1) и 2) - темплейты же, как shty написал.

invy ★★★★★
()

У меня был неудачный опыт общения с синглтонами в унаследованном коде. С тех пор их на дух не переношу.

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

trex6 ★★★★★
()
Ответ на: комментарий от JFreeM

Приведите хоть один пример, где он реально нужен и без него ну вот никак не жить

так можно далеко зайти. Зачем машина, если можно всюду пешком ходить.

alex_custov ★★★★★
()

Моя точка зрения синглтоны это часть нашей жизни. В питоне, например, модуль это синглтон. Да что там, даже обычная shared-либу можно обозвать синглтоном. Да и вообще у нас есть только одни stdin, stderr и stdout. Никто же не орёт что это несправедливо? Лепить их где попало не стоит, но так это и ежу понятно.

Что скажешь, лор?

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

Кто-то говорит, что goto — зло, но можно привести немало примеров, где использование goto делает код более простым, лаконичным и читаемым.

Так что вопрос в том, как использовать.

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

ien
()
Ответ на: комментарий от JFreeM

питон вообще говно


О, джавоилита в треде. Да ещё с такими аргументами - «вообще».

Virtuos86 ★★★★★
()

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

meil
()
Ответ на: комментарий от alex_custov

Приведите хоть один пример, где он реально нужен и без него ну вот никак не жить

так можно далеко зайти

Ну ты пример-то приведи :)

tailgunner ★★★★★
()

В питоне, например, модуль это синглтон.

Это такая шутка?

Да и вообще у нас есть только одни stdin, stderr и stdout.

Я правильно понял - ты считаешь stdin, stderr и stdout синглтонами? Как всё запущено.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Это такая шутка?

Это не шутка. Модуль это тоже объект и import или __import__ будут возвращать всегда одинаковый экземпляр. Не, ну ты можешь imp.reload() сделать, да...

ты считаешь stdin, stderr и stdout синглтонами?

нет, я запугиваю тем что концепция «что-то может существовать только в одном экземпляре» уже 30-40-50 лет с нами.

true_admin ★★★★★
() автор топика
Последнее исправление: true_admin (всего исправлений: 1)

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

drakmail ★★★★
()

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

class Receiver(Singleton, Greenlet):
  def _run(self, sock):
    while True:
      addr, data = sock.recv_from(config.RECV_BUF_SIZE)
      ...
receiver = Receiver(sock)

Ну и второй случай: для конфигов. Тут, правда, немного по-другому: есть функция get_config(namespace) которая либо создаёт новый объект, либо возвращает старый если он уже был создан. Такие «закешированные» объекты являются синглтонами?

true_admin ★★★★★
() автор топика
Ответ на: комментарий от true_admin

Это такая шутка?

Это не шутка

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

ты считаешь stdin, stderr и stdout синглтонами?

нет, я запугиваю тем что концепция «что-то может существовать только в одном экземпляре»

Мде. Для протокола: stdin, stdout и stderr - это глобальные константы, являющиеся указателями на «экземпляры» «класса» FILE. Синглтоны здесь вообще никаким боком.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от true_admin

Приведу пример как оно у меня используется

Вопрос не в «как», а в «зачем». Синглтон в приведенном коде нужен для... чего именно?

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Синглтон в приведенном коде нужен для... чего именно?

В конфигах: чтобы модули могли читать настройки друг друга.

Для receiver, sender и прочих сетевых функций: чтобы быть уверенным что второго инстанса обрабатывающего входящие пакеты нет, иначе будут проблемы. На всякий случай, в общем.

true_admin ★★★★★
() автор топика
Ответ на: комментарий от JFreeM

любую задачу можно решить без синглтона

Еще скажи, что без глобальных переменных.

Eddy_Em ☆☆☆☆☆
()

не так давно тоже искал ответ на этот вопрос. в результате наткнулся на http://users.livejournal.com/_winnie/18677.html. делай, как там написано - читай коментарии aruslan. так, чисто поржать. стиль изложения забавный ;)

aol ★★★★★
()
Ответ на: комментарий от anonymous

Используя DI синглтон становится автоматически не нужен.

Мде. Для протокола: stdin, stdout и stderr - это глобальные константы, являющиеся указателями на «экземпляры» «класса» FILE. Синглтоны здесь вообще никаким боком.

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

this

Суть синглтона же в том, чтобы в результате нескольких вызовов абстрактного

Singleton *foo = new Singleton();
В foo получался один и тот же объект (один и тот же указатель).

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

Как параметр:

int foo(Singleton &context, ...) {
  context.bar();
}

Поле:

int Zog::foo(...) {
  this.context.bar();
}

Но да, это неудобно, так как синглтон всё равно надо где-то хранить, чтобы его передавать в новые объекты. Один вариант — хранить его вместе с самим собой в статик-поле, то есть «обычный» синглтон. Другой вариант — хранить его в какой-нибудь AbstractFactoryBean-херне. Правда, саму херню тоже надо хранить в единственном экземпляре или обеспечить синхронизацию синглтонов, которые она может клепать. И это, походу, тоже обычный «синглтон».

Эээ... что-то мои рассуждения зашли в тупик.

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

// глобальная константа + обязательство не использовать new
Singleton *const foo = new Singleton();

// или то же самое, но с защитой от дебилов
class Singleton {
public:
  static getInstance() { return instance; }
private:
  Singleton(...);
  static Singleton *instance;
};
Singleton::instance = new Singleton(...);
// локальная переменная, притворяющаяся глобальной
int main() {
  Singleton foo();
  /* передавать &foo во всё, где он нужен */
}

Эти варианты могут быть обёрнуты во всякие DI, функции функций функций, но это не отменяет главного: синглтон = глобальная переменная. Отсюда естественным образом следует, что он не особо дружит с многопоточностью, тестированием, а также всё остальное, в чём его обвиняют ООП-фаги приверженцы ООП. [гений.жпг]

anonymous
()
Ответ на: комментарий от anonymous

не особо дружит с многопоточностью, тестированием

Ах да, ещё. Это не отменяет того, что обёртки могут всё это подправить и уменьшить вероятность выстрела в ногу. ФабрикуФабрикФабрик можно попросить вернуть вместо синглтона заглушку, а сам синглтон нормально синхронизировать. Другое дело, что иногда легче переписать без синглтонов, чем морочить себе голову всем этим. Но тут уже библиотеки спешат на помощь, где синглтоны клепаются одним Singleton<foo>.

anonymous
()
Ответ на: комментарий от tailgunner

stdin, stdout и stderr - это глобальные константы, являющиеся указателями на «экземпляры» «класса» FILE. Синглтоны здесь вообще никаким боком.

Чем глобальная константа-указатель принципиально отличается от синглтона? Суть же одна - у нас есть что-то только в одном экземпляре. По сути, мы можем одно и то же сделать двумя путями: глобальной переменной или, например, методом getInstance() или классом который всегда рожает один и тот же объект. Разницы же никакой, верно?

true_admin ★★★★★
() автор топика
Ответ на: комментарий от anonymous

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

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

true_admin ★★★★★
() автор топика

Короче, жавапроблемы.

Жавапроблемы подобного рода в Ъ-ынтерпрайзе решаются через DI и аннотации вроде @Singleton

anonymous
()

БыдлООПроблемы.

anonymous
()

Если одиночка доступен всем подряд, то это не есть хорошо. А если он поступает в виде инъекций только туда, где он нужен, то это очень даже неплохо.

CARS ★★★★
()

Синглтоны очень широко применяются в Scala (объекты-компаньоны).

dave ★★★★★
()

Основная беда с синглтонами, если они везде доступны - их начинают часто использовать, т.о. получаем кучу зависящих от синглтона объектов, увеличивается coupling, ухудшается модульность и взаимозаменяемость, etc etc etc.

yoghurt ★★★★★
()

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

cattail
()

одни stdin, stderr и stdout.

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

anonymous
()

Синглтон, безусловно зло.

1) Явные зависимости преобразуются в неявные. Если класс А зависит от класса Б, то было бы неплохо увидеть ссылочку в качестве поля, а не тупо висиячее обращение в коде.

2) Как выполнить обращение к синглтону через абстракцию? Если я хочу ссылочку интерфейсного типа на синглтон, то я вообще не представляю как это сделать, кроме как городить вспомгательные синглтоны-холдеры, буэээ. Dependency Inversion, мать его.

2) Синглтон нельзя просто взять, и заменить. Dependency Injection блеать.

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

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

dizza ★★★★★
()
Ответ на: комментарий от kemm

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

ВАЖНО! ПРОЧТИТЕ, ПОЖАЛУЙСТА!
ЭТА КНИГА - НЕ РУКОВОДСТВО К ДЕЙСТВИЮ, А СБОРНИК ИДЕЙ ДЛЯ ТВОРЧЕСКОГО ПЕРЕОСМЫСЛЕНИЯ.
КТО БУДЕТ «УЧИТЬ ПАТТЕРНЫ» НАИЗУСТЬ, ТОТ ЛОХ И ДЕБИЛ.
vasilenko ★★
()

ООП головного мозга - зло. А синглтоны никому не мешают, я гарантирую это.

anonymous
()
Ответ на: комментарий от vasilenko

Да хрен бы с ним, с творческим переосмыслением. Просто глядючи в иной код так и чувствуется мышление автора: «А-а-а-а!!! Мы сюда ещё не влепили Абстрактную Фабрику Абстракций™! Срочно делать, а то что мы как лохи!!!!111» Тьфублин. Занафейхуа идти от инструментов, а не от задачи, никогда не понимал.

kemm
()
Ответ на: комментарий от true_admin

Тут, правда, немного по-другому: есть функция get_config(namespace) которая либо создаёт новый объект, либо возвращает старый если он уже был создан.

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

gentoo_root ★★★★★
()
Ответ на: комментарий от vasilenko

Есть хорошая фраза на эту тему: «Чтобы понять, когда использовать %pattennname%, надо понять, когда используется %pattennname%». Ящитаю, изучение какого-либо паттерна должно начинаться фразой: «Ага, так вон тот велосипед, что я всё время городил, называется %pattennname%, и его лучше писать вот так».

anonymous
()
Ответ на: комментарий от anonymous

Ой, да хватит вам мусолить мелкие детали реализации. Сильно на результат не влияет это все, главное лишнего не городить.

dizza ★★★★★
()

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

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

baverman ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.