2016-12-22 38 views
1

考虑下面的代码:多态工厂

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

+0

唯一的办法是投''里面GetDrawer' Settings'。更多的面向对象解决方案是让'Settings'处理“通用”名称 - 值对,比如'settings.getInt(“width”)' – Arkadiy

+1

'DrawerFactory()'是没有意义的,因为DrawerFactory具有纯虚拟方法。 .. – jpo38

+0

jpo38:我知道它不会以我想要的方式工作,因此问题 –

回答

1

相反厂层次,你可以利用模板和专业化虚拟调度:

#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}); 
} 

[live demo]

0

在你的例子中,你的工厂似乎没有状态,所以你可以在没有多形工厂的情况下实现你想要的吗?例如,像这样...

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); 
} 

你可以使用重载而不是模板。

+0

我想避免在'DrawerFactory'中创建很多重载。这看起来像是将重载移出模板函数? –

+0

您的示例对于不同的设置类型(例如不同的硬编码数字)具有不同的行为。这些差异必须去某个地方。他们会去我评论有关使用设置的地方。它所做的是解决你描述的呼叫问题。 – ROX