2014-10-01 2 views
0

Я реализую шаблон фабрики для создания компонентов и хочу реализовать контейнер singleton для всех экземпляров каждого типа, созданного на заводе. В идеале это будет один вектор для каждого типа, созданного на заводе.Создатель компонента шаблона фабрики C++ с контейнером singleton

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

Я думал о делать что-то подобное для заводской карты:

Map<string,pair<constructorFnPtr, vector<baseClass>> 

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

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

Есть ли способ сделать то, что я пытаюсь сделать? Я пытался понять что-то за последние пару дней без везения.

Альтернативно, если есть другой хороший способ хранения векторов (то есть как статический член класса компонента), я также открыт для любых подобных предложений!

+0

попробуйте использовать 'dynamic_cast', где вы получите нужный вам тип, но если экземпляр не тот, он вернет null или throw:' dynamic_cast (myour_map ["instance"]. Second [0]) 'if" экземпляр "не является' TypeIWant', он вернет null или throw (на основе параметров компилятора) – Raxvan

+0

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

ответ

0

Вы не можете сделать это с помощью std :: vector смежных объектов.

Причина: фабрика должна строить объекты, а затем возвращать указатель на них. Проблема заключается в том, что указатель будет храниться вокруг вашего приложения, в то время как следующий вызов your_vector.push_back(), скорее всего, будет недействительными их, как C++ документация говорит:

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

Итак, ваш следующий звонок на завод может аннулировать все ваши предыдущие вызовы.

+0

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

+0

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

+0

Прямой указатель будет быстрее, пока вектор не будет расти, и каждый указатель на любой из его элементов станет недействительным. Спасибо за пользовательскую идею указателя, хотя я и не думал об этом, и это будет очень хорошо работать для меня! Хотел бы я придумать это неделю назад haha ​​ –

1

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

Я использую базу Component класс для всех компонентов. Это позволяет мне управлять некоторой статической информацией о времени выполнения для каждого компонента и выставлять набор общих методов. Затем я реализовал интерфейс IComponentPool, который является контрактом для моего пула объектов компонента. Затем я определил шаблонный класс ComponentPool<T>, который является производным от IComponentPool. Внутри этого класса шаблонов я управляю двумя векторами/массивами. Затем есть ComponentPoolMap, который предоставляет некоторое поведение, подобное карте, для поиска ComponentPool<T> на основе типов компонентов.

Теперь в классе ComponentPool<T> первый массив является разреженным массивом, используемым в качестве поиска. Он содержит смещение индекса, где компонент находится внутри второй плотной упакованной массива. Редкий массив может просто быть средством для принятия EntityId и конвертировать его туда, где находится компонент.Более сложная ручная система может быть легко реализована поверх этого типа фреймворка, если вы хотите.

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

Теперь шаблон фабрики, где вы создаете Entity или EntityId дескриптор объекта и создать все необходимые аспекты, которые составляют орк, зомби, или что-то для вашей игры. Завод действует как слой, который находится поверх вашей системы игровых объектов, из которых ваш ComponentPoolMap, скорее всего, является лишь небольшим фрагментом этой системы.

+0

Хороший ответ. У меня также есть вопрос. В другом сообщении (https://gamedev.stackexchange.com/a/59328) говорится, что создание функции типа EntityFactory :: CreatePlayer/CreateBullet * приводит к тому, что половина целей компонентного дизайна *, но ваше решение заявляет, что создание фабрично- функция для аспектов Orc/Zombie в порядке. Хотя я согласен с вами, я хотел бы услышать больше вашего ценного мнения на эту должность. Спасибо. – cppBeginner

+1

Автор просто указывает, что если вы можете поменять заводский метод создания Орка или Зомби в метод, управляемый данными, который может принять определение о том, как построить Орк/Зомби и выполнить ту же задачу, вы получаете способность выполнять быстрое прототипирование, что часто полезно при разработке. Фабричный метод - отличная отправная точка, которую вы можете легко реорганизовать в решение архетипа, основанное на данных, если вы обнаружите, что вам нужна или нужна такая гибкость. – Naros