static or singleton быть или не быть? И как быть?
От: 0x00  
Дата: 13.09.16 14:23
Оценка:
Доброго времени суток.
Возник вопрос по архитектуре, двоякая ситуация где можно использовать как singleton так и static.
Есть грубо говоря очередь рендера, наследовать\копировать как либо я не собираюсь и ограничиваюсь одним экземпляром.

Static
class IRender;

class RenderQuery
{
    static std::vector<std::vector<IRender *>> render_objects;

public:

    static void addObject(unsigned layer, IRender *object);
    static void delObject(IRender *object);
};


Singleton
class RenderQuery
{
    static RenderQuery *self;

    std::vector<std::vector<IRender *>> render_objects;

    RenderQuery();
    RenderQuery(const RenderQuery &);
    RenderQuery & operator =(const RenderQuery &);
    ~RenderQuery();

public:

    static RenderQuery * get()
    {
        if (!self) self = new RenderQuery();
        return self;
    }

    static void del()
    {
        if (self)
        {
            delete self;
            self = nullptr;
        }
    }

    void addObject(unsigned layer, IRender *object);
    void delObject(IRender *object);
};

RenderQuery *RenderQuery::self = nullptr;


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

Как вы поступаете в подобных ситуациях? И почему?
c++ architecture
Re: Singleton
От: Qbit86 Кипр
Дата: 13.09.16 14:36
Оценка: +2
Здравствуйте, 0x00, Вы писали:

0>Доброго времени суток.

0>Возник вопрос по архитектуре, двоякая ситуация где можно использовать как singleton так и static.

Предпочтительнее использовать Синглтон, то есть статический экземпляр обычного (нестатического, если не ограничиваться только C++) класса с нестатическими методами (то есть методами, вызываемыми у некоторого объекта/экземпляра).

Это упрощает потенциальный рефакоринг от Синглтона (который, как мы помним, зло) к протаскиванию зависимостей.
Код, который использует Синглтон, легко переделать в код, который просто использует нужный себе объект/экземпляр, ничего не зная о том, единственный ли он.
Глаза у меня добрые, но рубашка — смирительная!
Re[2]: Singleton
От: 0x00  
Дата: 13.09.16 14:41
Оценка:
Здравствуйте, Qbit86.

Спасибо за короткий быстрый и объемный ответ. Сэкономили на времени простоя в раздумьях)
Re[3]: ООП-излишества
От: Qbit86 Кипр
Дата: 13.09.16 14:51
Оценка: +1
Здравствуйте, 0x00, Вы писали:

0>Спасибо за короткий быстрый и объемный ответ. Сэкономили на времени простоя в раздумьях)


Когда оперируешь объектами, а не голыми функциями, на объекты несложно при необходимости навесить полиморфизм. Для RenderQuery можно ввести интерфейс IRenderQuery, и пропихивать его. Зачем? Ну, например, чтобы легко было временно подсунуть вместо RenderQuery его декоратор LoggingRenderQuery, который обмазывает вызовы инструментированием (замеры времени, логи, сбор статистики).
Глаза у меня добрые, но рубашка — смирительная!
Re[4]: ООП-излишества
От: 0x00  
Дата: 13.09.16 17:35
Оценка:
Здравствуйте, Qbit86, Вы писали:
Q>Когда оперируешь объектами, а не голыми функциями, на объекты несложно при необходимости навесить полиморфизм. Для RenderQuery можно ввести интерфейс IRenderQuery, и пропихивать его. Зачем? Ну, например, чтобы легко было временно подсунуть вместо RenderQuery его декоратор LoggingRenderQuery, который обмазывает вызовы инструментированием (замеры времени, логи, сбор статистики).

Раньше делал через интерфейс IRenderQuery но столкнулся с проблемой однозначности этого интерфейса, ведь я его наследовал от IQuery<T>, теперь же я решил упростить ситуацию и пришел к композиционной модели. В прочем мне ничего не мешает использовать наследование но только в случае интеграции. В случае с полиморфизмом иногда бывают ситуации Movable -> HorseMan -> Horse (помним о переопределении при наследовании) поэтому приходится инкапсулировать HorseMan в Horse. С этим что-то посоветуете? Иногда композиция выглядит логически неверной (ERECY!).
Re[5]: ООП-излишества
От: Qbit86 Кипр
Дата: 13.09.16 21:40
Оценка:
Здравствуйте, 0x00, Вы писали:

0>В случае с полиморфизмом иногда бывают ситуации Movable -> HorseMan -> Horse (помним о переопределении при наследовании)


Тут под стрелочками подразумевается наследование? Обычно стрелочки рисуются в обратную сторону от наследника к базовому классу. Это соглашение общепринято, и находит отражение в терминах типа «downcast», «upcast». HorseMan и Horse не должны быть связаны отношением IS-A, для моделирования которого используется наследование. В общем случае, иерархия не должна быть глубокой, и от конкретных классов не должно быть наследования. То есть каждый промежуточный класс в иерархии абстрактный, а каждый конкретный класс — «листовой» (sealed) — конец ветки, от него ничего не наследуется.

0>С этим что-то посоветуете?


Нет, тут нужно детали смотреть. Вряд ли стоит создавать развесистые иерархии.

0>Иногда композиция выглядит логически неверной (ERECY!).


Под «ERECY!» подразумевается «herecy»? :)
Глаза у меня добрые, но рубашка — смирительная!
Re[6]: ООП-излишества
От: 0x00  
Дата: 15.09.16 15:22
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>Тут под стрелочками подразумевается наследование? Обычно стрелочки рисуются в обратную сторону от наследника к базовому классу. Это соглашение общепринято, и находит отражение в терминах типа «downcast», «upcast». HorseMan и Horse не должны быть связаны отношением IS-A, для моделирования которого используется наследование. В общем случае, иерархия не должна быть глубокой, и от конкретных классов не должно быть наследования. То есть каждый промежуточный класс в иерархии абстрактный, а каждый конкретный класс — «листовой» (sealed) — конец ветки, от него ничего не наследуется.


Пишу слева на право потому что для меня это что-во что втекает, а не кто из кого истекает. Общепринято? А по каким "буквоам" гуглить гост?)

Q>Нет, тут нужно детали смотреть. Вряд ли стоит создавать развесистые иерархии.


(IRender IUpdate IEvent IEntity) <- Entity <- (Player, Light, Car etc)
(IRenderQuery IUpdateQuery IEventQuery) <- EntityManager
дальше я обычно создаю что-то вроде класса CustomStorage (а тут как быть если нужна еще и потокобезопасность?) в котором храню подсистемы аля ResourceManager, WindowManager, EntityManager, ParticleSystemManager, SpriteEffectManager, SoundEffectManager итд. Хранится все в
unordered_map<std::string, void *> storage;

(инкапсулированное поле класса).
Так и не придумал как лучше добавлять, автоматически — вызывая в конструкторах вышеописанных систем
CustomStorage::get()->addObject(std::string("Window"), static_cast<void *>(this));

Или мануально где-то например в main.
CustomStorage::get()->addObject(..., static_cast<void *>(WindowManager::get()));
CustomStorage::get()->addObject(..., static_cast<void *>(ResourceManager::get()));


0>>Иногда композиция выглядит логически неверной (ERECY!).


Q>Под «ERECY!» подразумевается «herecy»?

Да, не проверил перед отправкой)
P.S. Проверил, если где то теперь ошибся то из за своей неграмотности
самоучка во тьме видит проблеск фонаря.
Re[7]: Стрелки
От: Qbit86 Кипр
Дата: 15.09.16 15:29
Оценка:
Здравствуйте, 0x00, Вы писали:

0>Пишу слева на право потому что для меня это что-во что втекает, а не кто из кого истекает. Общепринято?


Писать можно как угодно, главное, чтобы стрелочки шли от наследников к предкам. Направление от наследника к предку это условно «вверх», от предка к наследнику — «вниз».

0>А по каким "буквоам" гуглить гост?)


По буквам UML, OOP, etc.
Глаза у меня добрые, но рубашка — смирительная!
Re: static or singleton быть или не быть? И как быть?
От: alpha21264 СССР  
Дата: 15.09.16 16:10
Оценка:
Здравствуйте, 0x00, Вы писали:

0>Доброго времени суток.

0>Возник вопрос по архитектуре, двоякая ситуация где можно использовать как singleton так и static...

Делаешь обычный класс, и сверху пишешь комментарий:
/*
Единственный экземпляр этого класса создаётся в файле файл.cpp
Если кто создаст другой экземпляр, будет депремирован на месячную зарплату.
Подпись: главный инженегр Иванов.
*/

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

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

Течёт вода Кубань-реки куда велят большевики.
Re[2]: Немного романтики.
От: 0x00  
Дата: 15.09.16 22:35
Оценка:
Здравствуйте, alpha21264, Вы писали:

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

A>Трольфейс-Трольфейс.

Хотелось бы достичь большей разумности архитектры, у вас же бывает так, пишешь класс, а потом просто дрочишь любуешься его красотой. Ровной табуляцией, логичной завершенностью и тем как красиво вписывается в программу, вот это и есть то ради чего стоит заморачиваться, иррациональное понимание архитектуры я бы сказал. Ну и хотелось бы конвертировать в рациональное. Т.к. буковы понимаешь, даже понимаешь что зачем куда и почему пихаешь, мартышку не пародируешь, но нету кристальной ясности, возникают двоякие ситуации.
Re: static or singleton быть или не быть? И как быть?
От: antropolog  
Дата: 15.09.16 23:42
Оценка:
Здравствуйте, 0x00, Вы писали:

0>Доброго времени суток.

0>Возник вопрос по архитектуре, двоякая ситуация где можно использовать как singleton так и static.
0>Есть грубо говоря очередь рендера, наследовать\копировать как либо я не собираюсь и ограничиваюсь одним экземпляром.

1. очередь рендера -> RenderQueue
2. лучше неймспейс

// RenderQueue.h
class IRender;
namespace RenderQueue {
  void add(unsigned layer, IRender* object);
  void remove(IRender* object);
};


// RenderQueue.cpp
#include "RenderQueue.h"
#include <vector>

namespace RenderQueue {
  static std::vector<std::vector<IRender *>> render_objects;
  
  void add(unsigned layer, IRender* object) {
    // implementation
  }
  
  void remove(IRender* object) {
    // implementation    
  }
};
Отредактировано 15.09.2016 23:46 antropolog . Предыдущая версия . Еще …
Отредактировано 15.09.2016 23:43 antropolog . Предыдущая версия .
Re[3]: Немного романтики.
От: alpha21264 СССР  
Дата: 16.09.16 09:45
Оценка:
Здравствуйте, 0x00, Вы писали:

0>Здравствуйте, alpha21264, Вы писали:


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

A>>Трольфейс-Трольфейс.

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


Мне кажется, у тебя эстетические критерии нафиг сбиты чтением неправильных книжек.
В моём варианте тебе русским (или английским) языком сказали, что это — синглетон.
В твоих вариантах (прочинанных в плохих учебниках) у тебя будет некий класс с
приватным конструктором. Конечно можно догадаться, что это — синглетон,
но когда пишешь программу, у тебя есть над чем подумать помимо расшифровывания
таких ребусов.

Программа, она вообще-то для человека (программиста) пишется.
Вот и пиши для человека — на человеческом языке.
Для машины любой дурак написать сможет. (с)
Ощущение крутости от понимания китайской грамоты конечно пропадёт.
Ну, будешь другими способами честолюбие удовлетворять.

PS.
Да, кстати, в C++ ещё namespace есть. Тоже способ синглетон сделать.

Течёт вода Кубань-реки куда велят большевики.
Re[2]: static or singleton быть или не быть? И как быть?
От: AlexGin Беларусь  
Дата: 16.09.16 10:05
Оценка:
Здравствуйте, alpha21264, Вы писали:
...
A>Ты, конечно скажешь, что найдётся идиот, который проигнорирует этот комментарий.
A>Но этот же самый идиот закоментирует слово static.
A>Трольфейс.
Может быть ситуация, когда другой программер не прочитает то, что ты там написал (тем более, если текст был по русски).
Очень маловероятно, что умышленно кто-то ПРОСТО ТАК "закоментирует слово static"!
Если этот кто-то задумает изменение архитектуры приложения...
Но это уже совсем другая история!
Re[2]: static or singleton быть или не быть? И как быть?
От: 4Real Швеция  
Дата: 21.09.16 02:25
Оценка:
Здравствуйте, antropolog, Вы писали:

A>1. очередь рендера -> RenderQueue

A>2. лучше неймспейс

А чем неймспейс лучше статического класса?
Re[3]: static or singleton быть или не быть? И как быть?
От: antropolog  
Дата: 21.09.16 13:28
Оценка:
Здравствуйте, 4Real, Вы писали:

R>А чем неймспейс лучше статического класса?


Основное преимущество — полная изоляция реализации ( для статического класса для этого нужен Pimpl ), второе преимущество — используя using легко менять имплементацию, ну и третье — меньше кода.
Re: static or singleton быть или не быть? И как быть?
От: Mr.Delphist  
Дата: 21.09.16 17:40
Оценка: +1 -1
Здравствуйте, 0x00, Вы писали:

0>было интуитивно понятно что экземпляр рендера должен быть один


Очень опасное самоуспокоение
Скажем, завтра портируем для каких-нибудь гугло-очков или телефона с двумя экранами — и вдруг опа, на каждый экран надо свой рендерер. Или пишем какой-никакой юнит-тест, и надо подоткнуть псевдо-рендерер. А у нас везде MyRenderer::getInstance() натыкан. Будет больно.

Код не должен знать, сколько экземпляров объекта. Он должен пользоваться тем экземпляром, что передан снаружи.
Re[2]: static or singleton быть или не быть? И как быть?
От: AlexGin Беларусь  
Дата: 22.09.16 08:11
Оценка:
Здравствуйте, Mr.Delphist, Вы писали:

MD>Здравствуйте, 0x00, Вы писали:


0>>было интуитивно понятно что экземпляр рендера должен быть один


MD>Очень опасное самоуспокоение

Но справедливое, если применяешь OpenGL!

MD>Скажем, завтра портируем для каких-нибудь гугло-очков или телефона с двумя экранами — и вдруг опа, на каждый экран надо свой рендерер. Или пишем какой-никакой юнит-тест, и надо подоткнуть псевдо-рендерер. А у нас везде MyRenderer::getInstance() натыкан. Будет больно.


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

Если тебе нужно два экрана, сначала следует отрендерить один, затем второй. Одновременно рендерить — это неправильно.

MD>Код не должен знать, сколько экземпляров объекта. Он должен пользоваться тем экземпляром, что передан снаружи.

Это вопрос дизайна архитектуры продукта.
Или на уровне дизайна, или на уровне реализации — следует запретить одновременное использование двух рендереров OpenGL.
Отредактировано 22.09.2016 8:14 AlexGin . Предыдущая версия .
Re[3]: static or singleton быть или не быть? И как быть?
От: Mr.Delphist  
Дата: 22.09.16 10:00
Оценка:
Здравствуйте, AlexGin, Вы писали:

AG>Здравствуйте, Mr.Delphist, Вы писали:


MD>>Здравствуйте, 0x00, Вы писали:


0>>>было интуитивно понятно что экземпляр рендера должен быть один


MD>>Очень опасное самоуспокоение

AG>Но справедливое, если применяешь OpenGL!
... OpenGL текущей реализации. А завтра выходит новый SDK/API/etc с откровением от авторов "мы тут подумали и поняли как несправедлив этот мир, бла-бла-бла... встречайте — concurrent rendering!"

MD>>Скажем, завтра портируем для каких-нибудь гугло-очков или телефона с двумя экранами — и вдруг опа, на каждый экран надо свой рендерер. Или пишем какой-никакой юнит-тест, и надо подоткнуть псевдо-рендерер. А у нас везде MyRenderer::getInstance() натыкан. Будет больно.


AG>Работая с OpenGL, убедился что именно такое решение — правильное!

AG>Второй рендерер — не будет корректно работать в другом потоке или процессе!
AG>Мы для этой цели — применяем мьютекс.

Всё верно: сейчас — ограничивайте мьютексом. Возникнет необходимость — откинете мьютекс и сделаете фабрику.

AG>Если тебе нужно два экрана, сначала следует отрендерить один, затем второй. Одновременно рендерить — это неправильно.

Если hardware/firmware поддерживают такое — почему нет? Вспомните, как сильно плевались в авторов игровых движков, когда массово пошли Hyper-Threading CPU и прочие многоядерники/многосокетники: одно ядро изжаривается с нагрузкой 146%, второе курит бамбук. Видяха ценой в половину компа недоумённо позёвывает и говорит "и это все полигоны, что у вас сейчас есть?"

MD>>Код не должен знать, сколько экземпляров объекта. Он должен пользоваться тем экземпляром, что передан снаружи.

AG>Это вопрос дизайна архитектуры продукта.
AG>Или на уровне дизайна, или на уровне реализации — следует запретить одновременное использование двух рендереров OpenGL.

На уровне реализации. Дизайн менять куда проблематичнее.
Re[4]: Vulkan
От: Qbit86 Кипр
Дата: 22.09.16 10:12
Оценка:
Здравствуйте, Mr.Delphist, Вы писали:

MD>... OpenGL текущей реализации. А завтра выходит новый SDK/API/etc


Уже вышел Vulkan же. OpenGL не нужен.
Глаза у меня добрые, но рубашка — смирительная!
Re[5]: Vulkan
От: AlexGin Беларусь  
Дата: 22.09.16 12:24
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>Здравствуйте, Mr.Delphist, Вы писали:


MD>>... OpenGL текущей реализации. А завтра выходит новый SDK/API/etc


Q>Уже вышел Vulkan же. OpenGL не нужен.

Спасибо, глянем
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.