CasDev
> ("божественный объект" - название антипаттерна).
Слышал о таком антипаттерне, но не могу сказать, что разве мой случай к нему относится.
Есть у класса Texture есть встроенный счётчик ссылок, который позволяет обращаться с текстурами как с типами значений. Можно создавать много копий одной текстуры, не думая о том, что они в самом деле копируются, что было бы достаточно медленно. Есть статический метод FromFile, который в своей базе ищет, загружена ли текстура, и если да, то увеличивает этот счётчик ссылок. При копировании этот счётчик ссылок тоже увеличивается. При вызове деструктора уменьшается.
То есть поведение отличается от обычной текстуры без счётчика + shared_ptr, так как shared_ptr реализует семантику ссылок. По сути текстуры управляют сами своим жизненным циклом. Они сами удаляются, когда становятся не нужны. Они сами исключают своё дублирование при загрузке из файла.
Разве это божественный объект?
CasDev
>Класс сам себя менеджить не должен, иначе это не класс, а какая-то помойка ("божественный объект" - название антипаттерна).
Тут не плохо бы пояснить что подразумевается под "менеджить" иначе я бы поспорил.
Не понятно к чему тут год обж был упомянут.
nes
В своем коде я стараюсь не пихать в класс те функции, которые классу не нужны.
К примеру, классу текстуры абсолютно не нужен счетчик ссылок.
Точно также базу текстур я тоже бы не хранил в классе текстуры, а использовал бы для этого менеджер текстур (банально чтобы не заставлять стороннего прогера, пользующего мой код, думать - а что же еще за каша скрыта в классе Texture, которая нужна как сбоку припека).
Раз все это есть - перед нами типичный god object.
CasDev
> К примеру, классу текстуры абсолютно не нужен счетчик ссылок.
Ну если ты не хочешь управляться с текстурами как со значениями, то может быть. А я хочу. Это очень удобно.
CasDev
> Точно также базу текстур я тоже бы не хранил в классе текстуры, а использовал
> бы для этого менеджер текстур
А что там хранить? map<string, Texture::RefCountedData*> - вот и весь менеджер. А то как насоздают всяких менеджеров не пойми чего, а потом получается неповоротливый Ogre, которого все ругают.
CasDev
> банально чтобы не заставлять стороннего прогера, пользующего мой код, думать -
> а что же еще за каша скрыта в классе Texture, которая нужна как сбоку припека
А чего там думать? Пользователь движка не должен думать о внутренностях. Захотел загрузить текстуру, написал
Texture tex1=Texture::FromFile("tex1.dds");
Захотел скопировать текстуру - написал
Texture tex2=tex1;
В часть этой текстуры можно рендерить, тогда произойдёт реальное копирование (Copy On Write) и будет две текстуры в видеопамяти: исходная и изменённая.
Так можно менять одну текстуру, не боясь попортить другие. Получается, что роль менеджера как бы берут на себя объекты, членом которых является эта текстура.
А что может ваш этот менеджер текстур?
Ух... Суровый челябинский менеджер.
gammaker
> В часть этой текстуры можно рендерить, тогда произойдёт реальное копирование (Copy On Write) и будет две текстуры в видеопамяти: исходная и изменённая.
жгите, жгите не останавливаясь :)
> а потом получается неповоротливый Ogre, которого все ругают.
Ogre как раз очень производительный для своих возможностей двиг, но плохо расширяем. (Вы кстати тот же подход используете, просто этого не понимаете).
Wraith
> Ух... Суровый челябинский менеджер.
Почему челябинский? Московский, я его в Москве придумал и реализовал. Только я не могу сказать, что это прям менеджер.
CasDev
> жгите, жгите не останавливаясь :)
Я пишу так, как у меня уже реализовано, а не просто свои идеи, которые я только что сгенерировал. И кстати, эта идея уже существовала до этого, но использовалась в основном только в классах строк (например QString из Qt).
CasDev
> Вы кстати тот же подход используете, просто этого не понимаете
Это вы судите по моему описанию класса текстур? И какие там проблемы с расширяемостью могут быть? Класс самодостаточен, у него нет лишних членов. Класс очень прост. Уверен, если писать отдельный менеджер, то там ботвы будет как целый класс текстуры. Но никто не запрещает ненасытному пользователю движка сделать свой отдельный менеджер текстур, базируясь на счётчике ссылок, если он захочет. Но если бы в движке не был предусмотрен счётчик ссылок, то его уже никак не добавить.
Да и вообще, а чего там расширять? Все типы (1D, 2D, 2DArray, 3D, Cube) и форматы (RGB и сотни других) текстур реализованы. За загрузку изображения из файла отвечает другой класс.
А у не-текстур вообще другой подход, так что вы не можете судить о нём.
CasDev
В данном случае соглашусь.
gammaker
> И какие там проблемы с расширяемостью могут быть? Класс самодостаточен, у него нет лишних членов.
Лады, я codemonkey, мне дали проЭхт, где используется твой класс текстуры.
И также у нас есть threadpool, где могут выполняться несколько важных длительных задач.
Допустим, в одном потоке я рендерю в текстуру (создаю допустим крутейший бакграунд, размываю слои и прочая), а в другом потоке использую результат.
Вопрос - а ВСЕ ЛИ ПРЕДУСМОТРЕНО в твоем крутом менеджере для данной задачи? И не будет ли архитектор проекта пыхать паром, стремясь узнать имя того, кто предложил использовать твой класс текстуры с неотделимым менеджером текстур от данного класса?
Берем второй проект.
В нем мы знаем, что в проекте под Android у нас будут использоваться текстуры РОВНО ОДНОГО ЕДИНСТВЕННОГО формата, а в проекте под iOS - другого и тоже единственного формата. В разработке же у нас будут использоваться все форматы, поскольку в процессе разработке мы класть хотели и на скорость загрузки, и на скорость работы. Поддерживать все форматы - пихать неиспользуемый код в .exe.
В случае с разделенным менеджером текстур и самими текстурами править придется совсем немного - и мы получим максимально производительный менеджер и минимально используемое окружение. В твоем случае мы либо начнем измываться над кодом путем расставления дефайнов по поводу и без, либо еще как.
Для просвещения - компонент.
nes
> Класс самодостаточен, у него нет лишних членов.
Ну, ежели бы твой класс именовался как MultiTextureCombineBasedOnReferenceCounterAndManagerInside, я бы с тобой легко согласился.
CasDev
Это не я писал )
Че глобальные переменные уже не катят, ООП типо рулит?
CasDev
> Допустим, в одном потоке я рендерю в текстуру (создаю допустим крутейший
> бакграунд, размываю слои и прочая), а в другом потоке использую результат.
Ну видеокарта-то одна. Если хочется работать с движком из разных потоков, надо использовать синхронизацию.
CasDev
> Лады, я codemonkey, мне дали проЭхт, где используется твой класс текстуры.
Мой класс текстуры неотделим от движка. Весь движок я делаю один, а пользователи уже пользуются.
CasDev
> Поддерживать все форматы - пихать неиспользуемый код в .exe.
Нет никакого кода. Формат - это просто некоторый enum. Переменная, которая хранится в объекте класса Texture. Или ты не про формат пикселя, а про формат файла? За это другой класс отвечает, Image, а также несколько классов-загрузчиков, каждый для своего формата. Сам класс Texture лишь использует Image::Load, который определяет тип файла и вызывает зарегистрированный для этого типа загрузчик. Ничто не мешает выпилить ненужные или добавить новые загрузчики без модификации остального кода.
Или по твоему понятию менеджер текстур за форматы файлов тоже отвечать должен?
CasDev
> Ну, ежели бы твой класс именовался как
> MultiTextureCombineBasedOnReferenceCounterAndManagerInside, я бы с тобой легко
> согласился.
Я же говорю, нет никакого менеджера, просто текстуры написаны так, что он им не нужен. Единственное, что есть из лишнего, так это база загруженных текстур, но не создавать же отдельно из-за неё менеджер.
А почему MultiTextureCombine?
gammaker
>Ну видеокарта-то одна. Если хочется работать с движком из разных потоков, надо использовать синхронизацию.
А есть ли в твоем классе текстур соответствующий lock для этого? Или поверх класса текстуры придется писать обертку "сЪ локомЪ"?
gammaker
> А почему MultiTextureCombine?
Потому что когда в коде видишь одну хрень, начинаешь подозревать вторую. Я ж твой класс не вижу, но тем не менее у тебя вполне возможен вариант.
Texture tex1, tex2; tex1 = Texture:: // загрузили tex2 = tex1; /* Начали рендерить в tex2. */ // Вопрос - та ли текстура у нас в tex2, что и в tex1? Правильный ответ - а хрен его знает, надо во внутренности лезть. // Ну и хорош ли этот код? Как по мне так не особо.
А где виднеется говноархитектура, говнокод себя ждать не заставит.
CasDev
> А есть ли в твоем классе текстур соответствующий lock для этого? Или поверх
> класса текстуры придется писать обертку "сЪ локомЪ"?
А откуда текстура может знать, рендеришь ты в неё или уже нет? Локай сам, когда начинаешь рендерить и анлокай, когда закончишь.
CasDev
> Вопрос - та ли текстура у нас в tex2, что и в tex1?
Я же написал как раз про этот случай. В tex1 лежит то, что в неё загрузили, а в tex2 будет лежать то, что в неё отрендерили. Ты знаешь, что такое копирование при записи (COW) и что такое тип значений?
То, что Texture - это тип значений, а не ссылочный тип, можно отразить в документации к движку.
Вы всё ещё пользуетесь своими референс коунтерами?
Тогда мы идём к вам.
Тема в архиве.