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()?

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

Но ведь ссылку на синглтон выдает статическая функция. Если она используется в коде, то как тогда обращаться к мок? Менять код?

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

Менять код?

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

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

Ну он типа на статической/глобальной переменной строиться. Но я понял о чём ты, что если не приделывать бонусом глобальную область видимости, а везде передавать ссылку на него явно, то всё тестируется. Да это так, но на практике все пользуются дополнительным «преимуществом». А те кто не пользуется - не имеют проблем с одиночками.

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

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

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

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

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

а везде передавать ссылку на него явно, то всё тестируется

Ага, именно. Кстати, есть еще методы еще более костыльные. Но не будем об этом=)

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

ссылку на синглтон выдает статическая функция

Вот тут и есть заблуждение.

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

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

Ну например так:

Добавляем в синглтон #ifdef TEST который будет активен только в конфигурации сборки под CI. в нем делаем френдом некий внешний метод. Констуркторы все приватные, десктруктор публичный. Внутри этого внешнего метода создаем объект и возвращаем(то есть фабрика, но только для юнит-тестов=) ).

То есть у насть есть возможность протестить синглтон на его функционал имея возможность создавать/удалять его в пределах одного тестового процесса.

Но:

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

2) Это требует уродования кода тест специфичными костылями=)

Я такой подходи никогда не использовал, если честно, но в голову он приходил.

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

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

Из проблем - придётся оставить код самой фабрики не протестированным, но он тривиальный, его мало, и можно поместить в шаблон.

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

фабричными методом-одиночкой.

И тащить ссылки на объект по цепочке через весь чейн? Для объекта который ГАРАНТИРОВАННО должен быть один в приложение? Сомнительное раздувание кода ж. Да и забивание стэка/памяти ненужными референсами(указателями).

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

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

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