Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.50/26: Рейтинг темы: голосов - 26, средняя оценка - 4.50
53 / 28 / 13
Регистрация: 01.03.2013
Сообщений: 330

IoC container вместо Singletone

27.02.2023, 08:47. Показов 5989. Ответов 79
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте.
В инете много инфы на эту тему, но она довольно не структурирована и сложно понять нужно ли вообще в это вникать на плюсах.
В общем есть приложение на Qt. В данном приложении много объектов-одиночек. Хотелось бы избавиться от них.
На первых парах не нашел какого-то встроенного инструмента в Qt. Есть мысли написать свой велосипед, но все же хотелось бы использовать проверенное решение.
Из того, что я понял контейнер зависимостей это некий класс, имеющий соответствующие методы - геттеры / сеттеры, полем которого выступает словарь {key, val}, где key это строка идентификатор, val - указатель на созданный объект. Но это какое-то слишком простое представление. Там еще фабрики каким то боком).
Рад буду любой ссылке либо на статью с подробным описанием решения моей проблемы, либо проекту на гитхабе (желательно максимально простому, не хотелось бы бездумно использовать какой-нибудь громоздкий инструмент на начальном этапе)
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
27.02.2023, 08:47
Ответы с готовыми решениями:

Класс Singletone
Здравствуйте! Продолжаю готовиться к экзамену по С++. На последнем уроке вкратце рассказали про класс Singleton, но я расслабился и...

Singletone и множество потоков
Всем доброго утра! В приложение есть множество потоков обращающихся к классу одиночки. Правильно ли я понимаю, что сам класс будет...

Белый экран при входе в админку - Class 'FOF30\\Container\\Container' not found
Добрый вечер! Помогите, пожалуйста, исправить проблемку. С джумлой раньше дел практически никаких не имел, поэтому прошу помощи у знающих...

79
 Аватар для eva2326
1685 / 513 / 107
Регистрация: 17.05.2015
Сообщений: 1,524
28.02.2023, 17:33
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Undisputed Посмотреть сообщение
Пока бред исходит только от вас.
Как интересно у вас получается: это вы путаете понятие типа с понятием паттерн, а бред якобы исходит от меня. Ну-ну.

Цитата Сообщение от Undisputed Посмотреть сообщение
То есть это не я придумал проблему
Нет, это именно вы придумали проблему.
ТС никаких проблем не озвучивал.

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

Цитата Сообщение от Undisputed Посмотреть сообщение
Вы опять потеряли контекст.
Попробуйте для разнообразия выражаться яснее.

Цитата Сообщение от Undisputed Посмотреть сообщение
Вот о чем я говорю:
Вы написали бред.

Вы вообще понимаете, что такое синглетон?
Синглетон Container<Data> невозможно сделать членом данных класса.

Вот эта фраза:
Цитата Сообщение от Undisputed Посмотреть сообщение
// если использовать getInstance вместо m_container, то мы заставляем все
    // передаваемые объекты обладать этим методом, что не гибко
Это какой то бессмысленный набор слов.
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
28.02.2023, 17:42
Цитата Сообщение от eva2326 Посмотреть сообщение
2. Если первый синглетон зависит от второго, тогда первому нужно сделать вызов второго у себя в конструкторе.
Проблема в том, что если вы имеете статические данные, то вызов конструктора ни чего не гарантирует. Нужно вызывать статические методы Майерса, в которых гарантирована инициализация после вызова метода (и прохода управления через объявления локальной статической переменной). Связывать конструктора, вероятно можно, прописывая указанные вызовы. Конструкторы синглтонов не доступны и вызываются через указанные статические методы. Таким образом можно обеспечить цепь таких вызовов не позволяя конструкторам синглтонов зависеть друг от друга. Однако, всё зависит от кейса и кекса. Особенно если кекс в кейсе. То что вы говорите реализуемо, Но вы говорите это так, будто я должен прослезиться и покаяться (или наоборот). Не буду.
Цитата Сообщение от eva2326 Посмотреть сообщение
А если учитывать?
Вы хотите от меня больше чем я хочу от вас. Гораздо.
0
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
28.02.2023, 17:57
Цитата Сообщение от eva2326 Посмотреть сообщение
Как интересно у вас получается: это вы путаете понятие типа с понятием паттерн, а бред якобы исходит от меня. Ну-ну.
Я уже отвечал на это. Это уже начинает смахивать на какую-то неадекватность или троллинг.

Цитата Сообщение от eva2326 Посмотреть сообщение
ТС никаких проблем не озвучивал.
А вот это уже явный бред.

Цитата Сообщение от eva2326 Посмотреть сообщение
что вы выдумали контекст
Я ничего не придумывал. С вами все в порядке?

Цитата Сообщение от eva2326 Посмотреть сообщение
Синглетон Container<Data> невозможно сделать членом данных класса.
Об этом я и говорю. Нужно выбирать
1) или вызывать getInstance в push что не гибко
2) или не использовать синглтон
Второй вариант предпочтительнее. Надеюсь теперь понятно.
0
28.02.2023, 18:02

Не по теме:

Спор как обычно перерос в терминологический
Каждый понимает термины на свой лад.

0
 Аватар для eva2326
1685 / 513 / 107
Регистрация: 17.05.2015
Сообщений: 1,524
28.02.2023, 18:58
Цитата Сообщение от Undisputed Посмотреть сообщение
А вот это уже явный бред.
Приведите цитату, где ТС якобы озвучил проблему с синглетонами.

Цитата Сообщение от Undisputed Посмотреть сообщение
Я ничего не придумывал. С вами все в порядке?
Нет, вы придумали несуществующую проблему.
Причем, единственное как вы смогли её обозначить, это вот такими словами:
Цитата Сообщение от Undisputed Посмотреть сообщение
Это как минимум лишило бы нас гибкости
Ну и что?
Гибкость ради гибкости не нужна.
Это не делает синглетон каким то неправильным.

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

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
 
template< template<class> class Container, typename Data>
class Queue
{
  using cont_t = Container<Data>;
    
  cont_t* m_container;
public:
  Queue(): m_container(&cont_t::get()){}    
  void push(const Data& e) { m_container->push_front(e); }
};
 
template<class t>class container
{
    container(){}
public:
    static container& get() { static container c; return c; }
    void push_front(const t&) { std::cout << "push_front...\n"; }
};
 
int main()
{
    Queue<container, int>().push(1);
}
А во-вторых, такого выбора в принципе на практике не возникает.
Это вообще какая то наивная позиция: рассуждать о предпочтениях в отрыве от реальной задачи.
Если по смыслу задачи нужен именно синглетон, то второй вариант уже не будет предпочтительным.

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

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

Цитата Сообщение от Undisputed Посмотреть сообщение
или вызывать getInstance в push что не гибко
Что в этом способе такого негибкого?
0
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
28.02.2023, 19:06
Цитата Сообщение от eva2326 Посмотреть сообщение
Приведите цитату, где ТС якобы озвучил проблему с синглетонами.
IoC container вместо Singletone
См. первое слово и далее по тексту Он потерялся, надо подсказать, что и как, вот и вся проблема.
Цитата Сообщение от eva2326 Посмотреть сообщение
Ну и что?
Гибкость ради гибкости не нужна.
Это не делает синглетон каким то неправильным.
Ого, я вижу вы все же признали что в данном контексте синглтон менее гибкий. Конечно, это не делает сам синглтон неправильным, но его применение в этом контексте неправильно. Можно стучать в дверь кувалдой, и это не сделает кувалду неправильной, но сделает само применение кувалды неправильным.
Цитата Сообщение от eva2326 Посмотреть сообщение
Это бред.
Во-первых, вам никто не мешает биндить переменную синглетона на указатель, или ссылку.
Не мешает, но это тоже не гибко. В вашем примере вы просто заменили getInstance на get. Этот пример так же требует наличие у контейнера метода get, который возвращает его объект, что так же не гибко. Я не смогу использовать например std::list с вашим контейнером. Вы всеми правдами и неправдами пытаетесь воткнуть синглтон туда, где ему не место <--- в этом ваша проблема.
Цитата Сообщение от eva2326 Посмотреть сообщение
Если по смыслу задачи нужен именно синглетон, то второй вариант уже не будет предпочтительным.
В отрыве от контекста так и есть. Но мы обсуждаем конкретную ситуацию, и вы кстати уже признали, что в этой конкретной ситуации использование синглтона это менее гибкое решение.

Цитата Сообщение от eva2326 Посмотреть сообщение
Например, есть некоторая система, в рамках которой может быть создан только и только один контекст устройства.
Я уже говорил об этом в почти в самом начале обсуждения. Это было как раз в том сообщении, за которое вы зацепились. Подчеркну, что я не противник синглтона, а сторонник использования инструментов по месту их назначения.

Думаю беседу можно завершить.
0
 Аватар для eva2326
1685 / 513 / 107
Регистрация: 17.05.2015
Сообщений: 1,524
28.02.2023, 19:24
Цитата Сообщение от Undisputed Посмотреть сообщение
См. первое слово и далее по тексту
В этом сообщении нет ничего ни о каких проблемах синглетонов.

Цитата Сообщение от Undisputed Посмотреть сообщение
Ого, я вижу вы все же признали что в данном контексте синглтон менее гибкий.
Это что ещё за бред?

Цитата Сообщение от Undisputed Посмотреть сообщение
но его применение в этом контексте неправильно.
С чего это вдруг неправильно?

Цитата Сообщение от Undisputed Посмотреть сообщение
Не мешает, но это тоже не гибко. В вашем примере вы просто заменили getInstance на get. Этот пример так же требует наличие у контейнера метода get, который возвращает его объект, что так же не гибко. Я не смогу использовать например std::list с вашим контейнером.
Это бред.

Во-первых, непонятно зачем, но технически ничего не мешает организовать поддержку самых разных типов.
Можно не только поддержать std::list, но и например, std::map.

А во-вторых, вы называете код, который рассчитан на работу с синглетоном не гибким, только потому что он рассчитан на синглетоны!

Это какой то лютый бред уже получается.

Цитата Сообщение от Undisputed Посмотреть сообщение
Вы всеми правдами и неправдами пытаетесь воткнуть синглтон туда, где ему не место
Нет, не пытаюсь.
Вы видимо забыли контекст беседы.
У нас изначально уже имеется очередь, которая работает с синглетоном.
Это вы, за каким то непонятным фигом хотите от него избавиться.
Непонятно зачем.


Цитата Сообщение от Undisputed Посмотреть сообщение
В отрыве от контекста так и есть. Но мы обсуждаем конкретную ситуацию, и вы кстати уже признали, что в этой конкретной ситуации использование синглтона это менее гибкое решение.
Бред.
Во-первых, я такого не признавала. Вы вообще адекватный?
В какой такой "этой конкретной" ситуации?
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
28.02.2023, 19:53
eva2326,
Цитата Сообщение от eva2326 Посмотреть сообщение
А во-вторых, вы называете код, который рассчитан на работу с синглетоном не гибким, только потому что он рассчитан на синглетоны!
Мне кажется , скорее наоборот.
Синглтоны называют негибкими, так как их нельзя использовать так же, как обычные классы.
Ну вот с той же очередью.
Допустим наш Синглтон имеет необходимый интерфейс для работы нашей очереди, но мы не можем его использовать в ней.
Нужна спец. очередь, и все остальное.
Не об этом ли все ?

Добавлено через 5 минут
Хотя шапка темы вот вообще не понятна, почему ТС решил избавится от Синглтонов.
Ну есть они, значит они для чего то нужны.
Зачем от них избавляться ?

Теперь чуть ниже :
Цитата Сообщение от Kenny7423 Посмотреть сообщение
Проблема скорее организационная. Изначально у меня объекты, которые требуют повсеместного использования (например Logs, Queue), переходили из класса в класс по ссылке в конструкторе, потом я их переделал под singleton, потому что параметров конструктора в некоторых классах стало слишком много. Далее я вычитал, что одиночки это чуть ли не антипаттерн и начал копать в сторону внедрения зависимостей.
Оказывается и синглтоны ему были не нужны

Добавлено через 1 минуту
Похоже автор сражается с ветряными мельницами.
0
 Аватар для eva2326
1685 / 513 / 107
Регистрация: 17.05.2015
Сообщений: 1,524
28.02.2023, 20:01
Цитата Сообщение от SmallEvil Посмотреть сообщение
Синглтоны называют негибкими, так как их нельзя использовать так же, как обычные классы.
Что бы сделать синглетон, нужно совершить ряд целенаправленных усилий.
Программист специально прилагает усилия, что бы в результате получился класс, который нельзя использовать как обычный класс.

Не знаю, что в голове у людей, которые обзывают синглетон негибким за их главную особенность, ради которой они и нужны.
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
28.02.2023, 20:27
Цитата Сообщение от eva2326 Посмотреть сообщение
Я тоже так думаю.
Поэтому мне и непонятно что вы обсуждали с Undisputed.

Цитата Сообщение от Kenny7423 Посмотреть сообщение
IoC container вместо Singletone
Мне пока это не понятно.
ОЗнакомился с Inversion of Control (инверсия управления) и Dependency Injection (внедрение зависимостей).
Но чем это поможет заменить Singltone - непонятно.
Так как я понял, объект - одиночка так и остается, на него навешивается некий интерфейс ?
И ради чего ?

Добавлено через 1 минуту
Цитата Сообщение от SmallEvil Посмотреть сообщение
И ради чего ?
Хотя даже не так.
Это просто обычная практика : создание интерфейсов для уменьшения зависимостей.
И никакого прямого отношения к Одиночкам она не имеет.
0
 Аватар для eva2326
1685 / 513 / 107
Регистрация: 17.05.2015
Сообщений: 1,524
28.02.2023, 21:15
Цитата Сообщение от SmallEvil Посмотреть сообщение
мне и непонятно что вы обсуждали с Undisputed
Он считает, что если шаблон очереди снабдить специальным параметром, который будет отвечать за underlying container, то это сделает шаблон класса более гибким.
Это действительно так и есть, вот только с синглетонами это никак не связанно.
А он этого понять никак не может.
Он почему то думает, что в негибкости версии без шаблоно-параметра виноват именно синглетон, а не отсутствие шаблонного параметра.
И даже тот факт, что в версиию с синглетоном можно просто добавить недостающий шаблоно-параметр, и тогда решение будет таким же гибким, его не смущает.

При этом он считает, что такое использование негибкой версии - это неправильное использование синглетона.
Что именно неправильно я так и не поняла.

Цитата Сообщение от SmallEvil Посмотреть сообщение
Но чем это поможет заменить Singltone - непонятно.
Да это вообще из разных областей))

Цитата Сообщение от SmallEvil Посмотреть сообщение
Но чем это поможет заменить Singltone - непонятно.
Это как мягкое с теплым.

Цитата Сообщение от SmallEvil Посмотреть сообщение
И никакого прямого отношения к Одиночкам она не имеет.
Не имеет.
0
 Аватар для lemegeton
4903 / 2696 / 921
Регистрация: 29.11.2010
Сообщений: 5,783
01.03.2023, 01:21
Цитата Сообщение от eva2326 Посмотреть сообщение
Приведите пример.
Серьезно?
Мне кажется это вполне очевидным.
Что-ж. Пожалуйста.

Рассмотрим ваш же пример синглтонов для логгинга, судя по неймингу.


Пишу я свой прекрасный класс, который что-то делает и пишет в лог, используя синглтон.
C++
1
2
3
4
5
6
7
class MyAwesomeService {
public:
    void doAwesomeStuff() {
        // do awesome stuff
        ::mylog::emergency.log("Done!");
    }
};
Все.
Теперь мой код ЗНАЕТ о существовании некоего лога и СВЯЗАН с ним.
Это увеличивает СВЯЗАННОСТЬ кода.
Тут заодно уменьшается связность кода, но это огрехи всех логгеров.
Этот код НЕВОЗМОЖНО использовать отдельно без функционала логгинга.
И как бы вы ни старались, другие примеры использования синглтона закончатся примерно так же.
Однако, если переделать под IoC и DI получится куда менее связанный код с тем же самым функционалом.
0
Эксперт функциональных языков программированияЭксперт Java
 Аватар для korvin_
4576 / 2775 / 491
Регистрация: 28.04.2012
Сообщений: 8,781
01.03.2023, 01:21
Цитата Сообщение от SmallEvil Посмотреть сообщение
Мне пока это не понятно.
ОЗнакомился с Inversion of Control (инверсия управления) и Dependency Injection (внедрение зависимостей).
Но чем это поможет заменить Singltone - непонятно.
Так как я понял, объект - одиночка так и остается, на него навешивается некий интерфейс ?
И ради чего ?
Это просто обычная практика : создание интерфейсов для уменьшения зависимостей.
Или не навешивается. DI и без интерфейсов может существовать. Только ТС не про это спрашивал.
Кликните здесь для просмотра всего текста
Цитата Сообщение от Kenny7423 Посмотреть сообщение
Проблема скорее организационная. Изначально у меня объекты, которые требуют повсеместного использования (например Logs, Queue), переходили из класса в класс по ссылке в конструкторе, потом я их переделал под singleton, потому что параметров конструктора в некоторых классах стало слишком много.
Было:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class A {
A(Logs* logs, Queue* queue, ...)
{
    _logs = logs;
    _queue = queue;
    ...
}
...
};
 
class B {
B(Logs* logs, Queue* queue, A* a, ...)
{
    _logs = logs;
    _queue = queue;
    _a = a;
    ...
}
...
};
 
class C {
C(Logs* logs, Queue* queue, B* b, ...)
{
    _logs = logs;
    _queue = queue;
    _b = b;
    ...
}
...
};
 
...
 
A *a = new A(logs, queue, ...);
B *b = new B(logs, queue, new A(logs, queue, ...), ...);
C *c = new C(logs, queue, new B(logs, queue, new A(logs, queue, ...), ...), ...);
...
Стало:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class A {
A()
{
    logs = Logs::instace();
    queue = Queue::instance();
    ...
}
...
};
 
class B {
B()
{
    logs = Logs::instace();
    queue = Queue::instance();
    a = new A();
    ...
}
...
};
 
class C {
C()
{
    logs = Logs::instace();
    queue = Queue::instance();
    b = new B();
    ...
}
...
};
 
...
 
A *a = new A();
B* b = new B();
C* c = new C();
или типа того.


Цитата Сообщение от SmallEvil Посмотреть сообщение
И никакого прямого отношения к Одиночкам она не имеет.
Прямого может и не имеет, но разница в том, что при использовании DI «одиночность» того или иного объекта может (и должен) задавать DI-контейнер, а не класс объекта, соответственно разработчику класса не нужно реализовывать этот паттерн, замусоривать им код класса и думать/помнить о всяких нюансах типа порядка инициализации (о чём писали выше), а сконцентрировать полностью на назначении класса.

В случае ТС DI-контейнер позволит (позволил бы) либо:
(Вариант 1) вернуть параметры конструкторов, чтобы иметь возможность передавать mock'и в тестах, например) и при этом создавать объекты в приложении без многочисленной передачи параметров:
Кликните здесь для просмотра всего текста

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class A {
A(Logs* logs, Queue* queue, ...)
{
    _logs = logs;
    _queue = queue;
    ...
}
...
};
 
class B {
B(Logs* logs, Queue* queue, A* a, ...)
{
    _logs = logs;
    _queue = queue;
    _a = a;
    ...
}
...
};
 
class C {
C(Logs* logs, Queue* queue, B* b, ...)
{
    _logs = logs;
    _queue = queue;
    _b = b;
    ...
}
...
};
 
...
 
A *a = DI::getInstance<A>();
B* b = DI::getInstance<B>();
C* c = DI::getInstance<C>();
или типа того.


Либо

(Вариант 2) не возвращать параметры конструкторов и обращаться к контейнеру переданному в качестве параметра, при этом ни контейнер, ни любой другой класс не реализует паттерн Синглтон, но сам контейнер определяет, какие объекты создаются каждый раз заново, а какие — только один раз. Контейнеры в тестах могут быть настроен по-другому и возвращать mock'и, например:
Кликните здесь для просмотра всего текста

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class A {
A(DI::Container* container)
{
    logs = container->getInstance<Logs>();
    queue = container->getInstance<Queue>();
    ...
}
...
};
 
class B {
B(DI::Container* container)
{
    logs = container->getInstance<Logs>();
    queue = container->getInstance<Queue>();
    a = container->getInstance<A>();
    ...
}
...
};
 
class C {
C(DI::Container* container)
{
    logs = container->getInstance<Logs>();
    queue = container->getInstance<Queue>();
    b = container->getInstance<B>();
    ...
}
...
};
 
...
 
A *a = container->getInstance<A>();
B* b = container->getInstance<B>();
C* c = container->getInstance<C>();
или типа того.


Первый вариант предпочтительней, т.к. нет зависимости классов от DI-фреймворка.
2
 Аватар для eva2326
1685 / 513 / 107
Регистрация: 17.05.2015
Сообщений: 1,524
01.03.2023, 05:07
Цитата Сообщение от lemegeton Посмотреть сообщение
Теперь мой код ЗНАЕТ о существовании некоего лога и СВЯЗАН с ним.
А проблема то в чем?

Я вам такой код приведу:

C++
1
2
3
4
5
struct student
{
  std::string name;
  std::size_t age;
};
Код, который использует данную структуру знает о существовании std::string, и о существовании std::size_t.
Ну и что?



Цитата Сообщение от lemegeton Посмотреть сообщение
Этот код НЕВОЗМОЖНО использовать отдельно без функционала логгинга.
Функционал - это в математике.

В программировании функциональность.

Что значит: "невозможно использовать отдельно без функционала логгинга" ?
Это вообще как понять?

Хотите удалить полностью логгирование, просто сотрите строчку с его использованием.
Хотите временно отключить логгирование, тогда позовите что-то вроде:
C++
1
::mylog::emergency.mode(DISABLE);
Хотите изменить логику работы emergency? Это же интерфейс. Нужно просто реализовать наследника с нужной логикой.

Я не понимаю, в чем проблема?

Цитата Сообщение от lemegeton Посмотреть сообщение
Мне кажется это вполне очевидным.
Не знаю, что именно вам очевидно.

Изначально вы обмолвились о каких то проблемах:
Цитата Сообщение от lemegeton Посмотреть сообщение
Использование синглтонов увеличивает связанность кода со всеми вытекающими проблемами
Но о каких именно проблемах, вы, по всей видимости, поведать не в состоянии.

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

Цитата Сообщение от lemegeton Посмотреть сообщение
Однако, если переделать под IoC и DI получится куда менее связанный код с тем же самым функционалом.
Приведите пример.
0
 Аватар для lemegeton
4903 / 2696 / 921
Регистрация: 29.11.2010
Сообщений: 5,783
01.03.2023, 10:38
Цитата Сообщение от eva2326 Посмотреть сообщение
Ну и что?
Как вы меряете качество кода?
Вы знаете что такое связанность (coupling) и связность (cohesion)? Крайне рекомендую к ознакомлению, чтоб не задавать таких вопросов.

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

Цитата Сообщение от eva2326 Посмотреть сообщение
Хотите удалить полностью логгирование, просто сотрите строчку с его использованием.
При переиспользовании кода?
При написании на код юнит-теста?
Может я хочу не удалить а заменить?

Цитата Сообщение от eva2326 Посмотреть сообщение
Приведите пример.
Уверен, вы скоро сами на всё наткнетесь, когда начнете писать что-то крупное.

В двух словах:

Singleton
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
    namespace MyAwesomeLibrary {
        template<typename T>
        struct Singleton {
            // ...
            static T *instance() {
                static T inst;
                return &inst;
            }
            // ...
        };
 
        struct VKConnector {
            void postImage() {
                // код, который ходит во внешний серввис
            }
        };
 
        struct MyAwesomeImagePostingService {
            void doSomethingAwesome() {
                // ...
                Singleton<VKConnector>::instance()->postImage();
                // ...
            }
        };
    }
    // ... пользуемся
    void postImageToVk() {
        MyAwesomeLibrary::MyAwesomeImagePostingService service;
        service.doSomethingAwesome();
    }
 
    // ... что делать, если через пол-года мне нужна другая реализацию?
    // переписывать?
    void postImageToIn100Grm() {
        // ???
    };
 
    // uint test?
    // мне нужно окружение поднимать? или писать код для отключения функциональности?
    // когда они как сухие макароны связаны стеком из 20-30 вызовов, это будет довольно неприятно
    void testPostImage() {
        MyAwesomeLibrary::MyAwesomeImagePostingService service;
        service.doSomethingAwesome(); // тут будет вызов сервиса, который мне не нужен для тестов
    }
IoC/DI
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
    namespace MyAwesomeLibrary {
        struct Connector {
            virtual void postImage() = 0;
        };
 
        struct VKConnector : public MyAwesomeLibrary::Connector {
            void postImage() override {
                // реализация
            }
        };
 
        struct MyAwesomeImagePostingService {
            MyAwesomeImagePostingService(Connector *connector) : connector(connector) {}
 
            void doSomethingAwesome() {
                connector->postImage();
            }
 
            Connector *connector;
        };
    }
 
 
    void postImageToVk() {
        // ...
        VKConnector connector;
        MyAwesomeLibrary::MyAwesomeImagePostingService service(&connector);
        service.doSomethingAwesome();
    }
 
    // ... через года расширяем функционал
    struct In100GrmConnector : public MyAwesomeLibrary::Connector {
        void postImage() override {
            // реализация
        }
    };
 
    void postImageToIn100Grm() {
        // ...
        In100GrmConnector connector;
        MyAwesomeLibrary::MyAwesomeImagePostingService service(&connector);
        service.doSomethingAwesome();
    }
 
 
    // ... в юнит тесте
    struct MockConnector : public MyAwesomeLibrary::Connector {
        void postImage() override {
            // do something I like
        }
    };
 
    void testPostImage() {
        // ...
        MockConnector connector;
        MyAwesomeLibrary::MyAwesomeImagePostingService service(&connector);
        service.doSomethingAwesome(); // вызовется мой мок
    }
3
631 / 526 / 104
Регистрация: 05.08.2022
Сообщений: 2,810
01.03.2023, 11:05
Я вот читаю ветку и никак не могу понять: откуда вообще берётся противопоставление Singleton и IoC/DI ?
Это же какие-то абсолютно перпендикулярные вещи.
Singleton - как гарантированно сделать единственный экземпляр класса.
IoC/DI - как развязать классы, например передавая интерфейсы для реализации "внешних" функций (функционала в смысле). При этом "внешний интерфейс" может быть и Singleton, а может и не быть.

Тогда почему Singleton и IoC/DI вообще сравниваются / противопоставляются?

lemegeton выше привёл пример. Это отлично, это хотя бы позволяет предметно что-то обсуждать, а не кидаться на оппонента.
Но в чем проблема именно Singleton в приведённом примере? а если бы это не Singleton, а просто класс, экземпляр которого мы запихали в другой класс - это что, отменит проблему? да ни на грамм. При чем здесь тогда Singleton ?
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
01.03.2023, 11:16
eva2326, когда вы (и не только вы) говорите, так как будто от ваших слов дрожит земля и на неё падает небо, хочется куда-то спрятаться. Вот пример игры понятиями в ключе общее-частное:
Цитата Сообщение от eva2326 Посмотреть сообщение
вы путаете понятие типа с понятием паттерн,
Но это же норма жизни. Функтор-паттерн, функтор-класс, функтор-объект. В хорошей литературе, даже присутствуют длинные оговорки об употреблении данных терминов в текущем тексте. С синглтоном та же ситуация. Синглтон это объект одиночка. Его одиночность связана сждопустимым набором операций (конструктор это функция/операция - и он недоступен среди допустимых операций). То есть, в языке С++ по крайней мере, синглтон реализуется на уровне типа. Типы бываь разные, - синие зелёные, красные... Но есть те что очень локальны и применимы лишь в ограниченном круге задач, а есть и такие, что обобщают на уровне идиомы какую то концепцию. Такие вещи называют идиомами. Их реализация для симейства типов обобщающих концепцию применения и функционирования называется паттерном. Синглтон тут не исключение.
Теперь о холиваре. Этот зверь может быть рассмотрен минимум в 3-х базовых ипостасях: спорт, наука, искусство. Вот вы говорите:
Цитата Сообщение от eva2326 Посмотреть сообщение
Я вам такой код приведу:
struct student
C++
1
2
3
4
{
  std::string name;
  std::size_t age;
}
;
Хм... Давайте пойдём стандартным путём матидеотизма, то есть попробуем развалить применяемые абстракции методом забодания их границ вплоть до разрушения.
Начнём с конца. Ваш студент не может двигаться со скоростью выше скорости света, так как его возраст не может убывая стать отрицательным. Я не спорю даже с тем, что он изменяется только на целое количество единиц. Лет наверное. Ещё хуже, то что что изучая теорию относительности студент может попасть в дурку. И не факт что вылечится. То есть, он не будет знать своего имени от слова совсем.
eva2326, я тоже защитник всего действительного из числа разумного. Я тоже вижу, что неймспейсу с набором данных и функций, не будет хватать операций, и возможности наследовать. Неймспейс нельзя передать параметром в функцию, сокрыть данные и пр. Родителем наш одиночка быть не может ввиду недоступности конструктора. Но это его основная фича. А достоинство без недостатков, это как Пьер без ухОв.
Готов вас поддержать в том, что - пусть живёт. Но готов и поспорить на предмет того, что - пусть живут и все остальные. В каком-то смысле мы все одиночки)
0
 Аватар для lemegeton
4903 / 2696 / 921
Регистрация: 29.11.2010
Сообщений: 5,783
01.03.2023, 12:05
Цитата Сообщение от KSergey9 Посмотреть сообщение
Я вот читаю ветку и никак не могу понять: откуда вообще берётся противопоставление Singleton и IoC/DI ?
Всё верно. Они связаны лишь косвенно в рамках этого обсуждения.
Проблема с паттерном синглтон может возникнуть только при его использовании.
Если нужная сущность передаётся в класс параметром конструктора -- сама реализация паттерна синглтона теряет смысл.

Цитата Сообщение от IGPIGP Посмотреть сообщение
Давайте пойдём стандартным путём матидеотизма, то есть попробуем развалить применяемые абстракции методом забодания их границ вплоть до разрушения.
Отличная идея. )))


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

Цитата Сообщение от IGPIGP Посмотреть сообщение
когда вы (и не только вы) говорите, так как будто от ваших слов дрожит земля и на неё падает небо, хочется куда-то спрятаться.
Агрессивное и высокомерное поведение не делает человека правым, зато делает его неприятным собеседником.
Смотрите на аргументы.
0
 Аватар для eva2326
1685 / 513 / 107
Регистрация: 17.05.2015
Сообщений: 1,524
01.03.2023, 12:38
Цитата Сообщение от lemegeton Посмотреть сообщение
Вы знаете что такое связанность (coupling) и связность (cohesion)?
Да.

Цитата Сообщение от lemegeton Посмотреть сообщение
Крайне рекомендую к ознакомлению, чтоб не задавать таких вопросов.
В том то и дело, что я в курсе что такое "связанность".
Именно поэтому я предложила вам проиллюстрировать проблемы.

И сейчас вы будете пытаться высосать их из пальца.

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

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

Цитата Сообщение от lemegeton Посмотреть сообщение
В том, что это скрытый контракт -- поди догадайся через пять лет, что этому классу нужен какой-то синглтон и попробуй удовлетворить эту потребность.
Это бред.
Есть такое понятие: "инкапсуляция".
Клиентам в принципе не нужно ничего гадать, и даже думать на эту тему.
А разработчикам в принципе нужно знать, что там внутри.

Кстати, тема инкапсуляции к синглетонам отношения не имеет.

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

Цитата Сообщение от lemegeton Посмотреть сообщение
Уверен, вы скоро сами на всё наткнетесь, когда начнете писать что-то крупное.
У меня есть опыт крупных проектов.
И даже очень крупных.
И даже очень очень крупных.
Вот только на "всё" я так и не наткнулась.

Цитата Сообщение от lemegeton Посмотреть сообщение
// ... что делать, если через пол-года мне нужна другая реализацию?
    // переписывать?
Не вижу причин, зачем переписывать то, что итак работает.

За использование конкретной реализации отвечает этот узел:

Цитата Сообщение от lemegeton Посмотреть сообщение
struct MyAwesomeImagePostingService {
            void doSomethingAwesome() {
                // ...
                Singleton<VKConnector>::instance()->postImage();
                // ...
            }
        };
Если вам нужно иметь возможность указывать тип коннектора, просто возьмите, и укажите его:

C++
1
2
3
4
5
6
        struct MyAwesomeImagePostingService {
            template <class Connect>
            void doSomethingAwesome() {
                Singleton<Connect>::instance()->postImage();
            }
        };
Вообще, в зависимости от ваших потребностей, можно сделать как угодно.
Можно по аналогии с логгерами предоставить пользователям втыкать любое количество своих собственных синков.

Цитата Сообщение от lemegeton Посмотреть сообщение
мне нужно окружение поднимать? или писать код для отключения функциональности?
Конечно ))

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

Цитата Сообщение от lemegeton Посмотреть сообщение
IoC/DI
Приведенный вами код ничем принципиально не отличается от синглетоновский версии.

Сравните:

C++
1
2
3
4
5
6
7
// синглетон
struct MyAwesomeImagePostingService {
    template <class Connect>
    void doSomethingAwesome() {
        Singleton<Connect>::instance()->postImage();
    }
};
C++
1
2
3
4
5
6
void postImageToVk() {
    // зависимость в конструкторе
    VKConnector connector;
    MyAwesomeLibrary::MyAwesomeImagePostingService service(&connector);
    service.doSomethingAwesome();
}
Единственное различие лишь в том, что в первом случае клиент указывает неккий идентификатор нужного ему метода.
Это не обязательно должен быть тип, это вообще может быть какой нибудь enum.
Поэтому, можно сделать так, что бы клиентам вообще не нужно было знать ни о каких деталях, даже об интерфейсах.
А во втором случае, клиентам придется быть в курсе существования наследников, и знать про их интерфейс.

Но вот именно с точки зрения метрик качества кода, разницы вообще нет никакой.

Выше вы жаловались:
Цитата Сообщение от lemegeton Посмотреть сообщение
В том, что вместе со своим кодом приходится таскать все зависимости, которые могут быть не нужны или не иметь смысла в другом месте.
Однако зависимости таскать придется в обоих случаях.
Никуда вы от этого не ушли, и уйти не сможете.
Вот только не все зависимости, как вы выразились, а только инфраструктурные (обвяз из интерфейсов).
А вот наследников таскать с собой не обязательно.

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

Добавлено через 8 минут
Цитата Сообщение от lemegeton Посмотреть сообщение
Если нужная сущность передаётся в класс параметром конструктора -- сама реализация паттерна синглтона теряет смысл.
Это ещё почему?

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

И с чего это синглетон вдруг потерял смысл только потому, что ему там что-то передали в конструкторе ???
0
 Аватар для lemegeton
4903 / 2696 / 921
Регистрация: 29.11.2010
Сообщений: 5,783
01.03.2023, 12:52
Цитата Сообщение от eva2326 Посмотреть сообщение
просто возьмите, и укажите его
Поздравляю, вы изобрели простенький DI.
Даже контракт у класса на методе появился.
Лишняя зависимость от класса Singleton только осталась.
Но может быть так и задумывалось.
Если передать сущность через конструктор -- можно и от неё избавиться.

Цитата Сообщение от eva2326 Посмотреть сообщение
Конечно ))


Цитата Сообщение от eva2326 Посмотреть сообщение
У меня есть опыт крупных проектов.
И даже очень крупных.
И даже очень очень крупных.
Вот только на "всё" я так и не наткнулась.
Значит недостаточно крупные. Крупнее, ЕЩЁ КРУПНЕЕ!
Чтоб было сотни приложений, в которых библиотеки использовали библиотеки, которые используют библиотеки, использующие библиотеки в библиотеках библиотек.
И всё это с TDD на ста окружениях и с интеграцией с тяжелыми внешними системами.
И всё это компанией из сотен постоянно меняющихся разработчиков по всему миру на протяжении 10-15 лет.

Цитата Сообщение от eva2326 Посмотреть сообщение
Для классов, которые используют синглетоны, юнит тесты пишутся абсолютно точно так же, как и для любых других классов.
Ну если вы локально поднимаете какое-то моковое окружение для юнит-тестов -- мои вам соболезнования.

Цитата Сообщение от eva2326 Посмотреть сообщение
Сравните:
Замечательный аргумент.
Вы ИЗМЕНИЛИ мой код, и теперь говорите что это одно и то же. )))

Цитата Сообщение от eva2326 Посмотреть сообщение
Единственное различие лишь в том, что в первом случае клиент указывает неккий идентификатор нужного ему метода.
Прикинь, да? Это и есть самое большое различие. Указание внешней зависимости.
Как мы это называем? Именно. Dependency Injection.

Цитата Сообщение от eva2326 Посмотреть сообщение
Это не обязательно должен быть тип, это вообще может быть какой нибудь enum.
Или реализация интерфейса, переданная в конструкторе/методом...

Цитата Сообщение от eva2326 Посмотреть сообщение
Поэтому, можно сделать так, что бы клиентам вообще не нужно было знать ни о каких деталях, даже об интерфейсах.
Да конечно можно.
Интерфейс в этом случае используют лишь для одного -- фиксирование явного контракта.
Можно сделать шаблонным параметром и описать в документации, чего он там должен уметь.
А можно болт положить на документирование и пущай пиры гадают.

Цитата Сообщение от eva2326 Посмотреть сообщение
Однако зависимости таскать придется в обоих случаях.
Цитата Сообщение от eva2326 Посмотреть сообщение
Никуда вы от этого не ушли, и уйти не сможете.
Я явно показал, как избавиться в компоненте от зависимости от Singleton'а и конкретики реализации.

Цитата Сообщение от eva2326 Посмотреть сообщение
а только инфраструктурные (обвяз из интерфейсов).
Слово потерялось. Инфраструктурные что?

Цитата Сообщение от eva2326 Посмотреть сообщение
Я пока что не увидела от вас никаких проблем связанных с тем, что синглетоны увеличивают связанность кода.
Конечно. Вы просто поменяли мой пример под себя.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
01.03.2023, 12:52

Singletone для Class library
приветствую всех, Каждый раз в каждом class где я работаю с class library я создаю объект. Говорят это не есть хорошо. ...

Паттерн singletone и unit of work
Изучаю паттерн unit of work.Чета я не сильно понял чем он отличается от singletone.И тот и тот создают только одну копию обьекта.Только...

IoC контейнер
Добрый день! Подскажите пожалуйста, как использовать IoC контейнер, например Ninject Использую EF. Создал Контекст: public class...

Spring ioc
Всем привет. Немного запутался по поводу ioc-контейнера. Что стоит отдавать ему под управление? К примеру сейчас столкнулся с такой...

DI/IoC из коробки
Вышел NET 4.7.2 , а вместе с ним приятные плюшки для форм: ASP.NET Поддержка внедрения зависимостей в веб-формах Внедрение...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Оказывается, Unreal Engine позволяет качество на порядки выше, чем было в Lineedge
Etyuhibosecyu 05.07.2026
Жаль, конечно, что я не узнал об этом, пока Lineedge существовала, а то бы Noname2331 написал, что волки превращаются в пиксельную кашу, а я бы его попросил скачать какую-нибудь бриллиантовую или Pro. . .
Doom для терминала без стрельбы и монстров. 3D Raycasting на ascii.
dcc0 05.07.2026
Попросил нейронную сеть deepai. org написать рейкастинг 3D с библиотекой ncurses для Linux. Чтобы можно было ходить на стрелочки. Чтобы стены были отрисованы символами. Справилась. Первый вариант. . .
Установка статуса документа по условию
Maks 05.07.2026
Алгоритм из решения ниже реализован на нетиповом документе "НарядПутевка" разработанного в КА2. Задача: в табличной части "Материалы" документа при записи автоматически устанавливать статус. . .
Сезонность и суточность закисления почв
anaschu 04.07.2026
200 часов это все равно моловато. Есть ситуации, но нестандартные, когда смена происходит за 5 лет. Но обычно это 50 лет и более. Наверное, закисление почвы происходит сезонно в средней. . .
В чем ценность человеческого опыта в глобальном смысле?
kumehtar 03.07.2026
Возможно, ценность человека не в том, что он однажды достигает мудрости, а в том, что он становится носителем карты пути. Он знает не только истину, но и последовательность внутренних изменений,. . .
интеграция AnyLogic с самописным REST API и переход на Odoo
anaschu 03.07.2026
Успешная интеграция AnyLogic с самописным REST API и переход на промышленную Odoo WMS Сегодня проделал огромный путь от простой симуляции физических процессов до построения полноценной. . .
Поиск всех путей на ориентированном графе. Linux
dcc0 02.07.2026
Переработка старого кода из моей статьи. Через несколько переработок от PHP кода к C89 (надеюсь, 89). Но довольно запутанно получилось. Код для Linux. Но если убрать time и то, что с ним. . .
Сам себя обучал rest api
anaschu 02.07.2026
Педагогический лайфхак: Почему чистый REST API для ученика намного круче, чем готовые библиотеки Когда мы отказались от капризного JAR-файла AnyLogic и переписали код на стандартный HttpClient,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru