LINUX.ORG.RU

Как обычно создается синглтон: наследованием или прямым кодом?

 , singletone,


2

3

Нигде не нашел внятного ответа на простой вопрос.

В программе нужно иметь несколько синглтонов, например один из вариантов синглтона Майерса:

class CMySingleton
{
public:
  static CMySingleton& Instance()
  {
    static CMySingleton singleton;
    return singleton;
  }

// Other non-static member functions
private:
  CMySingleton() {}                                  // Private constructor
  ~CMySingleton() {}
  CMySingleton(const CMySingleton&);                 // Prevent copy-construction
  CMySingleton& operator=(const CMySingleton&);      // Prevent assignment
};

Как такие классы-синглтоны правильнее создавать? Просто надо наследоваться от вышеуказанного CMySingleton, или надо напрямую привести хидер обычного класса к такому же состоянию и прописать реализацию метода Instance()?

★★★★★
Ответ на: комментарий от seiken

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

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

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

Например, синглтон для хранения и работы с настройками программы выглядит вполне себе здраво.

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

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

Временно захардкодить/выключить настройки отдельного модуля уже никак

В этом нет проблемы. Если она у тебя есть, то ты где-то что-то делаешь сильно не так, как надо. Разные настройки для разных кусков программы одновременно - это нештатное поведение by design и тестировать в нём что-то ССЗБ, а если они не разные у тебя как раз есть одно место, откуда всё можно захардкодить при желании.

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

Если «грамотность архитектуры» заключается в простоте расширения и взаимозаменяемости элементов системы, синглтон может и не мешать, если он реализован один раз и не меняется в течение всего жизненного цикла ПО. Если речь идет о простоте тестирования, код синглтона можно проверить другими методами тестирования, не ЮТ.

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

Если речь идет о простоте тестирования, код синглтона можно проверить другими методами тестирования, не ЮТ.

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

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

Разные настройки для разных кусков программы одновременно - это нештатное поведение by design

Необязательно, очень может быть именно штатное by design. Например, из какого-либо источника (файл/БД) могут загружаться данные + параметры их обработки, а эти параметры обработки - часть настроек программы.

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

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

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

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

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

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

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

deep-purple ★★★★★
()

Нигде не нашел внятного ответа на простой вопрос.

следовательно вопрос не прост: как создать синглтон

а вопрос как создят синглтон для ( и тут перечисление как этот синглтон и для чего тут синглтон

таким образом синглтон в плюсах не есть «аксиоматический» (как точка и прямая в геометрии) а синглтон в плюсах зонтичный термин используемый в разных контесктах для обозначения одного и того же но используемое в самих кодах по разному и в зависимости от использования есть разное его(синглтона) конструирования и тут ещё всё это запутывается не ортоганальностью плюсов ещё большей чем пюрешкаСи.

задавайте ваши ответы.

qulinxao3 ★☆
()
Ответ на: комментарий от deep-purple

тестирование, являясь лишь внешним дополнительным инструментом

Это только лишь с позиций just for fun, а не software engineering

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

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

slackwarrior ★★★★★
()
Последнее исправление: slackwarrior (всего исправлений: 2)
Ответ на: комментарий от pon4ik

В 99% случаев singleton это акт отчаяния, за редкими и очень редкими исключениями.

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

Можно ли как-то это сделать без синглтона или некоего глобального объекта? Т.е. решить задачу доступа к неким данным из любого места программы. Это на Qt.

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

В общем случае не решается в том виде как ты её представил. Просто это в принципе дизайн для наколенного поделия не рассчитаного как минимум на тестирование. Конкретно в Qt это уже сделано в виде синглтона - QApplication уже содержит настройки достаточно переопределить бэкэнд для QSettings.

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

Конкретно в твоём случае, проблема как минимум в том, что окошки (представления) содержат в себе логику сложнее «уведомить модель о действии пользователя» или «рисовать так».

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

В том же Qt вполне себе удачная точка для размещения бизнес логики это модель, обычно, для не сложного ПО это одно, максимум 2 дерева. О5 же - дизайн сиглтонов в Qt оставляют возможность покрыть код тестами, абстрагируясь от любой их логики, кроме самого цикла обработки сообщений. Поэтому, использовать QSettings из QApplication - впринципе нормальная идея, в духе фреймворка и есть точки для подмены.

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

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

pon4ik ★★★★★
()

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

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

Сейчас можно так:

Не можно, в примере выше статический метод Instance() должен создавать синглтон, а все кто вовне - нет.

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

Потому что синглтоны — жирнющее глобальное состояние-клей.

Нет, не потому что синглтон - говно, а потому что синглтон хреново спроектирован.

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

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

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

Синглтоны не позволяют писать нормальные unit-тесты.

Почему невозможно? И что такое нормальные юнит-тесты?

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

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

А такая фабрика не будет ли синглтоном сама по себе?

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

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

this.

Dudraug ★★★★★
()
Ответ на: комментарий от deep-purple

Все что ты сказал правда, но только для случая если у тебя 1-2 разраба в команде. Команда из сотни и более человек, которая разрабатывает серьезный продукт, без CI попросту или обречена на провал проекта вообще, или на увеличение сроков разработки, ибо разбиение процесса разработки на независиссимые параллельные под-проекты становится крайне затруднительной.

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

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

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

Синглтоны не позволяют писать нормальные unit-тесты.

Можно пример?

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

И почему это плохо? Если объект класса А использует объект класса В (не важно, синглтон В, или нет), то в любом случае объект класса А зависит от В и соответственно без В его нельзя использовать вне зависимости от того, является ли В синглтоном или нет.

Следить что ты один - это дополнительная ответственность для класса…

Это достаточно элементарный код.

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

По поводу бэкэнда: тыц

По поводу «содержится» тыц

Для пользователя это выглядит как создание объекта, но в потрохах оно вроде как не пересоздаётся даже.

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

Но она вправе возвращать ссылку на такой объект прозрачно для пользователя.

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

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

По поводу «содержится» тыц

Так ведь объект QSettings не содержится в QOpplication. Ты его должен сам создавать.

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

но при этом, этот вариант хорошо тестируется

«Этот вариант» - это фабрика возвращающая синглтон? Можно пример? И еще пожалуйста напиши, в чем удобство тестирования этого варианта, а в чем неудобство тестирования синглтона мейерса.

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

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

deep-purple ★★★★★
()
Ответ на: комментарий от Dudraug

Серьезно или шутите?

  1. тест не может удалить синглтон перед запуском или сбросить объект в начальное состояние.
  2. невозможно запустить несколько тестов параллельно.
  3. все объекты, что связаны с синглтоном, на практике, косвенно, тоже становятся статическими. Миллионы книг по проектированию об этом пишут.
xor2003
()
Ответ на: комментарий от rumgot

без В его нельзя использовать вне зависимости от того, является ли В синглтоном или нет.

Если объект B не синглтон, то можно создать mock объект и протестировать A изолированно. Как по вашим словам - сложную систему из объектов, только целиком тестировать.

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

Пример писать лень, может оказаться не лень на выходных, если пнёшь.

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

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

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

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

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

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

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

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

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

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

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

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

невозможно запустить несколько тестов параллельно.

В пределах одного тестового процесса невозможно, но нескольких вполне. У нас например на CI-сервере гоняется под несколько десятков (если не сотен) парарлелльных очередей.

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

Ну такое себе... Тогда и любая глобальная функция делает компонент-клиент статическим. Я не вижу большой разницы между функцией malloc(или оператором new) и синглтоном, который менеджит память на кольцевых буферах статического размера. Но по вашей логике первое не создает связанности, а второе да?

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

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

Если объект B не синглтон, то можно создать mock объект и протестировать A изолированно. Как по вашим словам - сложную систему из объектов, только целиком тестировать.

Создать мок на синглтон - это не проблема.

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

Про майерса - его нельзя пересоздать, соответственно - нельзя смокать

Я или туплю или не понимаю почему, не вижу проблем написать мок/стаб на синглтон по майерсу.

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