Рассмотрим следующий код:
template <typename T>
class DrawerFactory
{
protected:
DrawerFactory() {};
private:
virtual shared_ptr<IDrawer> GetDrawer(T settings) = 0;
};
class ConcreteDrawerFactoryA : public DrawerFactory<SettingsA>
{
public:
shared_ptr<IDrawer> GetDrawer(SettingsA settingsA) override
{
if (settingsA.style == A) return make_shared<ConcreteDrawerA>(settingsA.length, settingsA.stroke, settingsA.opacity);
else return make_shared<ConcreteDrawerB>(20, .5);
};
};
class ConcreteDrawerFactoryB : public DrawerFactory<SettingsB>
{
public:
shared_ptr<IDrawer> GetDrawer(SettingsB settingsB) override
{
if (settingsB.type == TYPEC) return make_shared<ConcreteDrawerC>(settingsB.width, settingsB.height);
else return make_shared<ConcreteDrawerD>(10, 2);
};
};
Я могу получить ящик по:
ConcreteDrawerFactoryA().GetDrawer(settingsa);
или же
ConcreteDrawerFactoryB().GetDrawer(settingsb);
Что я хотел бы сделать, это:
DrawerFactory().GetDrawer(settingsa);
DrawerFactory().GetDrawer(settingsb);
Есть ли способ настроить это без необходимости постоянно добавлять перегрузки DrawerFactory
для каждого конкретного завода я хочу добавить?
Вместо фабричной иерархии и виртуальной диспетчеризации вы можете использовать шаблоны и специализацию:
#include <memory>
struct IDrawer { };
struct Drawer1: IDrawer { };
struct Drawer2: IDrawer { };
struct Drawer3: IDrawer { };
struct Drawer4: IDrawer { };
template <class T>
struct DrawerGetterImpl;
struct DrawerFactory {
template <class T>
std::shared_ptr<IDrawer> GetDrawer(T settings) {
return DrawerGetterImpl<T>::GetDrawer(settings);
}
};
struct SettingsA { int style; };
template <>
struct DrawerGetterImpl<SettingsA> {
static std::shared_ptr<IDrawer> GetDrawer(SettingsA settings) {
if (settings.style == 1) {
return std::make_shared<Drawer1>();
}
return std::make_shared<Drawer2>();
}
};
struct SettingsB { int type; };
template <>
struct DrawerGetterImpl<SettingsB> {
static std::shared_ptr<IDrawer> GetDrawer(SettingsB settings) {
if (settings.type == 1) {
return std::make_shared<Drawer3>();
}
return std::make_shared<Drawer4>();
}
};
int main() {
DrawerFactory().GetDrawer(SettingsA{1});
}
В вашем примере ваша фабрика, казалось, не имела состояния, так что вы можете достичь того, чего хотите, без полиморфной фабрики? Например что-то вроде этого …
template<class T>
std::shared_ptr<IDrawer> MakeDrawer(T settings);
template<>
std::shared_ptr<IDrawer> MakeDrawer<SettingsA>(SettingsA settings)
{
return std::make_shared<ConcreteDrawerA>(); // use settings really
}
template<>
std::shared_ptr<IDrawer> MakeDrawer<SettingsB>(SettingsB settings)
{
return std::make_shared<ConcreteDrawerB>(); //use settings here
}void main()
{
SettingsA setA;
std::shared_ptr<IDrawer> pA = MakeDrawer(setA);
SettingsB setB;
std::shared_ptr<IDrawer> pB = MakeDrawer(setB);
}
Вы можете использовать перегрузки вместо шаблонов.