2016-12-22 71 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