Пара вариантов:
Переосмыслите свое использование
Абстрактная фабрика полезна, если она отделяет пользователя фабрики от того, как создается точный тип. Абстрактная фабрика не имеет никаких ограничений на то, что она производит, просто она абстрактна. Он может возвращать неабстрактный тип или абстрактный тип, который не лежит в основе вашей иерархии наследования.
Если код, использующий фабрику, уже может получить разные наборы данных для вызова фабрики, то код, использующий фабрику, уже знает о типе, который из него получается.
Вот несколько вариантов для размышления:
- Укажите несколько абстрактных типов фабрики, с одним методом
Create
, таким как GrenadeFactory
и BulletFactory
- Предоставление нескольких методов для одного абстрактного типа фабрики, таких как
CreateBullet
и CreateGrenade
- Хватит использовать абстрактные фабрики. Это хороший вариант, если вам действительно не нужна абстрактная конструкция , и вам просто нужны абстрактные типы.
Помните, что вы все равно можете передать производный тип (Bullet
) в метод, принимающий базовый тип (скажем, Entity
или Projectile
).
Двойная отправка
Если вы действительно настроены на объединение абстрактных фабрик с абстрактными параметрами, то вам может потребоваться двойная диспетчеризация или Шаблон посетителя . Ключевым моментом здесь является то, что вы пытаетесь объединить два разных виртуальных метода и получить уникальную комбинацию поведения на основе этих двух производных типов.
Это потребует от вас создания базовых и производных типов для ваших параметров, чтобы вы не могли передавать простые типы (например, int, string и т. Д.) Без создания пользовательской структуры параметров, производной от базового Parameters
типа.
Для реализации шаблона Visitor также требуется много дополнительного кода.
RTTI
Вы можете использовать функцию информации о типах C ++ .
Используя dynamic_cast
, вы можете привести базовый тип к производному типу. Вы можете сделать это в реализации фабрики, чтобы привести базовый тип параметра к вашему конкретному типу параметра.
Как и двойная диспетчеризация, для этого также потребуется создать иерархию типов для параметров, но потребуется меньше кода для их соединения (не требуется шаблон посетителя).
Однако эта опция будет тесно связывать вашу фабричную реализацию с реализацией структуры параметров.
Имущественная сумка
Вы также можете использовать словарь string
-> some type
(например, string
-> boost::any
). Это называется сумкой свойств. Тем не менее, он теряет большую безопасность типов времени компиляции, потому что вы в основном просматриваете все по строковому значению. Я не очень рекомендую это.