| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > так ли плох синглтон |
| Автор: GoldFinch 5.8.2009, 10:15 |
| в английской википедии, в статье про синглтон ( http://en.wikipedia.org/wiki/Singleton_pattern ) есть пяток ссылок ([1]-[6], http://en.wikipedia.org/wiki/Singleton_pattern#cite_note-0) на статьи в которых говорится что синглтон это антипаттерн так например пишут что синглон это не ООП, а замена глобальных переменных на глобальные функции, что синглтон реализует "i know where you lives" антипаттерн, и повышает число скрытых зависимостей /discuss |
| Автор: Lazin 5.8.2009, 10:23 |
| В общем случае наверное да, но есть ситуации, в которых это не так. Я для себя выработал такое правило: объект может быть глобальным, только если его состояние не изменяется или для приложения не важно его состояние, например логгер и стандартные потоки ввода вывода, у них есть состояние, но как правило, приложению фиолетово, что выводили в лог или в поток минуту назад. Сам подумай, передавать в каждый объект указатель на std::cout или %loggername% - глупо. |
| Автор: azesmcar 5.8.2009, 10:27 |
| Ссылки на высказывания людей с сомнительным авторитетом. Андрей Александреску около 30-и страниц этому шаблону проектирования, а Алексу Миллеру (кто это такой вообще?) вдруг взбрело в голову что это зло. Бегу удалять синглтоны Разумеется не надо строить свой код на одних синглтонах, но есть ситуации когда без него никак. Тот же логер, настройки и многое другое. |
| Автор: GoldFinch 5.8.2009, 10:29 |
| Lazin, std::cout - не синглтон. это обычная глобальная переменная. и это часть стандартной библиотеки у std::cout есть состояние, оно изменяется манипуляторами и флагами. но допустим, логгер может быть синглтоном, а все остальное - не может. значит синглтон плох, а логгер - это исключение из правила? |
| Автор: Любитель 5.8.2009, 10:35 | ||
В идеале - да. |
| Автор: Acer 5.8.2009, 10:59 | ||
А если я делаю структуру с обьектами класса конфигурации, а так же с обьектом класса, который пишет лог и указатель на экземпляр этой структуры у меня передается в другие модули приложения? так тоже глупо? хочу совет |
| Автор: Lazin 5.8.2009, 11:27 | ||||
да, но если не пользоваться манипуляторами(или правильно ими пользоваться), то иногда можно считать что его нет |
| Автор: Earnest 5.8.2009, 12:23 |
| Что за странная постановка вопроса? Даже GOTO не является безусловным злом. "Все есть яд и все есть лекарство". Просто голову нужно применять почаще. Насчет приложения. Допустим, у меня есть куча объектов типа логгер (т.е. ровно один инстанс на сесссию). Какой-нибудь менеджер событий, очередь чего-нибудь глобальная, регистраторы разные, да мало ли. И что, по вашей логике, я их все из объекта-пртложения должна получать? И во что тогда объект-приложение превратиться? При том, что информация о как минимум половине этих объектов ему нафиг не нужна для нормальной жизни. Наоборот, преимущество синглетона в том, что он ни от кого не зависит и гарантирует единственность. Более того, семантика синглетона прекрасно расширяется на более сложные случаи, например, один экземпляр в потоке, или один экземпляр в документе, причем ни поток ни документ совершенно не должны знать об этих конкретных объектах. Т.е. это прекрасное средство для устранения лишних зависимостей. Так что я синглетоны люблю. Но пользоваться ими надо не бездумно. Как и всем остальным, впрочем. |
| Автор: azesmcar 5.8.2009, 12:31 |
| Earnest Полностью согласен. Злом считаю не синглтон, а антипатерн "Золотой молот", когда человек изучив синглтон пытается его внедрить во все мыслимые и немыслимые щели. |
| Автор: GoldFinch 5.8.2009, 12:33 | ||
зависимости никуда не деваются. они просто становятся неявными, убираются из интерфейса в реализацию если объекту не надо с чем-то взаимодействовать - то он не должен об этом знать, а если надо - это должно быть написано в интерфейсе объекта Добавлено через 13 минут и 52 секунды
по моей логике должно быть queue = new SomeQueue(); eventMan = new EventManager(queue); если логгер не имеет состояния, то он вобщем-то и не объект, (у объекта есть внутреннее состояние, которое изменяется вызовом его методов) и то как организован доступ к этому логгеру - через глобальную переменную, глобальную функцию или еще как - не важно. для "объекта" без состояния нет разницы между Logger log; ... log.write(...); или Logger::Instance().write(...); или Logger_write(...); |
| Автор: mes 5.8.2009, 12:49 | ||
Earnest, в понятие паттерна синглетон входит случай лишь когда класс объекта, сам регулирует единичное кол-во своих инстанций или когда некто внешний регулирует кол-во инстанций равным в нашем случае единице ? |
| Автор: Earnest 6.8.2009, 06:53 | ||
| mes, я и не имею в виду, что описанные расширения продолжают быть синглетоном. И потом, каноническое описание паттернов - это что евангелие новое? Смысл паттернов в том, чтобы дать пример логической организации кода и побудить к творчеству. А где гарантия того, что каждый второй клиент не начнет создавать свои очереди? Синглетон же гарантирует единственность. А что касается зависимостей - ты не прав. Нет там никакой зависимости на уровне реализации, во всяком случае можно так сделать. И вот это высказывание
более чем спорно. Для одного интерфейса может быть несколько реализаций: одни с зависимостями, другие без... Кроме того, зависимости можно приблизительно учитывать как "прямого видение" определения класса \интерфейса \ функции. Так что когда зависимости только в реализации - их безусловно меньше. |
| Автор: Любитель 6.8.2009, 07:10 |
| Ну вот взять тот же логгер. Допустим у нас есть реальный Logger, с записью куда-нибудь и отсылкой нотификейшенов на e-mail и есть FakeLogger - для тестов. Работаем с логгером мы только через ILogger. Синглетон в чистом виде - явно не пойдёт. Нужна какая-то фабрика логгеров. Она же управляет временем жизни. И вообще созданием подобных объектов должны управлять DI-фреймворки |
| Автор: Lazin 6.8.2009, 07:37 |
| ох уж эти enterprise программисты |
| Автор: azesmcar 6.8.2009, 08:23 | ||
По моему тут больше подойдет препроцессор #ifdef _DEBUG. Зачем нагружать программу фабрикой логеров для тестирования? |
| Автор: chaos 6.8.2009, 08:32 | ||||||
как вариант логгер который пишет plain text, логгер который пишит в xml формате или логгер который шлет все на мыло или еще куда Добавлено через 4 минуты и 40 секунд
офтоп небольшой PocoCapsule например, больше не встречал готовых реализаций DI\IoC |
| Автор: azesmcar 6.8.2009, 08:39 | ||||
Такое я бы реализовал передав ему аргумент writer какой нибудь, создать единый интерфейс для logwriter -а, наследовать от него xmlWriter, mailWriter и plainWriter например...а дальше так
ну или что-то наподобие этого. В коде можно будет различать случаи, когда нужно послать на мейл или вывести в log file. |
| Автор: Любитель 6.8.2009, 09:31 | ||||
Почему я не имею права запускать юнит-тесты на релизе?! Ещё и пересобирать.. Не, не хочу Вопрос, как таковой, не имеет отношения к С++ (точнее так - отношениее имеет, не имеет прямой привязки), так что...
1. В твоём примере полиморфизм не сработает - ты передаёшь объект по ссылке. 2. У тебя просто writer выполняет то, что я называл логгером. Да-да, мы такие |
| Автор: azesmcar 6.8.2009, 09:40 | ||||||||
Я думал речь идет о простом тестировании, но название препроцессора всегда можно изменить #ifdef UNIT_TEST или как там? Компилятор что-то там определяет точно.
Одна поправка, константную ссылку, но что это меняет? с чего ему не работать? Полиморфизм работает как по указателю так и по ссылке. Правда я на скорую руку написал, просто идею показать..тут больше бы подошел статический полиморфизм на мой взгляд.
так например.
Ну это я для примера написал, разумеется это не идеальный код, я саму идею имел ввиду. А кстати фабрика логеров это тоже лишний уровень абстракции. |
| Автор: GoldFinch 6.8.2009, 10:57 | ||
| azesmcar, статический полиморфизм - он статический, а надо, чтобы в ран-тайме можно было дать объекту логгер, обычный, продвинутый, или Null-логгер. фабрика - это не уровень абстракции, а вспомогательный объект\класс, не влияющий на абстракцию того что она производит объекты же не знают как и произвели - просто создали, создали на фабрике или клонировали Добавлено @ 10:59 azesmcar, а юнит тест это
|
| Автор: azesmcar 6.8.2009, 11:02 | ||||
Кто это так решил что надо? Я писал как раз о том, чтобы сделать это во время компиляции а не в рантайме, потому как не увидел смысла оставлять это на рантайм.
Да, но уровень абстракции нужен для работы фабрики. Я знаю что такое юнит-тест. Что ты этим хотел сказать? Студия насколько я помню при генерации шаблона юнит тестов определяет какие-то конкретные макросы, можно использовать их или же определить свой собственный в настройках проекта в конце концов. |
| Автор: mes 6.8.2009, 11:08 | ||||||
По контексту обсуждаемого поста это не следовало.
Конечно нет, но логично предположить, что обсуждение синглетона в данной теме, исходя из поста тс, ведется именно в рамках его канонического описания
Правильно, взять лучшее и постараться исключить плохое. Плохое, имхо, это контроль класса над временем жизни , способом и кол-вом создаваемых инстанций. Правда после внесения изменений синглетон перестает быть синглетоном |
| Автор: GoldFinch 6.8.2009, 12:43 |
вот тут полиморфизма вообще нет. |
| Автор: azesmcar 6.8.2009, 12:48 |
это тебе так кажется. Это статический полиморфизм. |
| Автор: GoldFinch 6.8.2009, 12:49 |
| fixed. Добавлено через 33 секунды было бы typedef ... logger_t; ... logger_t::Instance()->write(...); был бы полиморфизм. хотя совсем не понятно, почему не просто logger_t::write(...); (то что используется вызов метода по указателю, ->write(...); могло бы использоваться для виртуального метода, но это же не тот случай) Добавлено через 2 минуты и 59 секунд какбэ запись Logger<XMLWriter> совершенно эквивалентна Logger_XMLWriter а вот template<typename W> Logger<W> это совсем другое |
| Автор: azesmcar 6.8.2009, 12:53 | ||||
что такое logger_t??? Куда он пишет и как дать понять куда я хочу писать? В XML Или в Plain text?
Каким образом вызов метода по указателю связан с виртуальным методом?
Но я как раз хочу сказать что динамический полиморфизм тут совершенно не нужен (ну или я не понял зачем он нужен, может у автора есть причина). |
| Автор: mes 6.8.2009, 13:02 | ||
это как раз и проявление статического полиморфизма. Неважно какой тип, главное чтоб он обладал нужным интерфейсом Добавлено @ 13:04 Ну а вообще мне кажется, что в Вашем споре между GoldFinch и azesmcar, каждый спорит о своем.. Неплохо бы прояснить в чем суть то спора |
| Автор: GoldFinch 6.8.2009, 13:11 |
| ну вообще тема про синглтоны |
| Автор: azesmcar 6.8.2009, 13:13 | ||||
я не понял чем мой вариант отличался от "совсем другого"?
Я и сам не знаю |
| Автор: GoldFinch 6.8.2009, 13:22 |
| azesmcar, а зачем объекту надо решать, кто куда ему будет писать? это уже много обязанностей, когда объект и основную работу выполняет и решает куда ему лог писать. другое дело, что объекту нужен логгер для логов - ему дают логгер (не каждый объект должен вести логи) а вот нужно вести лог вообще, или в какой файл или не файл этот лог должен вестись - решает тот кто объект создает. если лог не нужен, объекту дают null-логгер который ничего не делает, если нужно писать в файл или в сокет дают соответствующий логгер. а статически или динамически - другой вопрос, будет это class Foo { Foo(ILogger* log) ... }; или template<typename LOG> class Foo { Foo(LOG& log) ... }; или template<typename CFG> class Foo { Foo(CFG::logger_t log) ... }; Добавлено через 1 минуту и 38 секунд там что класс Writer жестко задан, и его никак не поменять |
| Автор: azesmcar 6.8.2009, 13:28 | ||
template<typename W> Logger<W> Как ты будешь использовать этот класс?
не так что ли? |
| Автор: GoldFinch 6.8.2009, 13:36 |
| azesmcar, я имел ввиду template<typename W> ... { Logger<W>::write("text"); } и ... { Logger<ConcreteWriter>::write("text"); } это ведь разные вещи? как например AbstractFoo* foo; foo->write("text"); и ConcreteFoo* foo; foo->write("text"); |
| Автор: azesmcar 6.8.2009, 13:43 | ||
Где-то его все равно надо будет конкретизировать. Я показал именно конкретизированную часть, хочешь передавай конркетный врайтер в функции main, какая разница. Это решается в зависимости от требований. |