c++模板實現抽象工廠

相似於rime的rime::Class<factory type, product type>實現方式。

 

C++模板實現的通用工廠方法模式

1.工廠方法(Factory Method)模式函數

工廠方法模式的意義是定義一個建立產品對象的工廠接口,將實際建立工做推遲到子類當中。核心工廠類再也不負責產品的建立,這樣核心類成爲一個抽象工廠角色,僅負責具體工廠子類必須實現的接口,這樣進一步抽象化的好處是使得工廠方法模式可使系統在不修改具體工廠角色的狀況下引進新的產品。spa

工廠方法模式結構示意圖.net

工廠方法模式是簡單工廠模式的衍生,解決了許多簡單工廠模式的問題。首先徹底實現‘開-閉 原則’,實現了可擴展。其次更復雜的層次結構,能夠應用於產品結果複雜的場合。指針

工廠方法模式很好用,但在代碼層面上,爲每個產品都編寫一個對應的工廠,這無疑很麻煩,並且不一樣的Product要寫不一樣Creator。想一想你在寫一個GUI庫,基本控件爲Widget類,由其派生下了TextBoxButtonLabel等幾十個控件,那你須要爲這幾十個控件分別編寫對應的ConcreteCreator。天,這太麻煩了吧!而若是你還要寫一個RPG小遊戲,須要從Person類派生下如NPCHeroEmenyAlly等又是十幾個類,並且還要編寫一個對應於PersonCreator....對象

 

2.模板實現工廠方法模式blog

   面對這種類型形成的多態,C++模板就要出場了。如今狀況是這樣的,ProductConcreteProduct都已經寫好,咱們要爲其編寫對應的工廠類。能夠看出來,Product對應對CreatorConcreteProduct對應於ConcreteCreator。也就是說,若是想編寫通用的ConcreteCreator,就得將ConcreteProduct抽象,想編寫通用的Creator,就得將Product抽象。而咱們最後會將這2者都抽象了。接口

   首先編寫通用的ConcreteCreator遊戲

 

[cpp]  view plain copy
 
  1. // 具體工廠類  
  2. // Product爲抽象產品,ConcreteProduct爲具體產品  
  3. template<typename Product, typename ConcreteProduct>  
  4. class ConcreteCreator  
  5. {  
  6. public:  
  7.     // 生產一個具體產品  
  8.     static Product* createProduct()  
  9.     {  
  10.         return new ConcreteProduct();  
  11.     }  
  12. };  

 

注意createProduct()是靜態的,是由於該函數要被保存起來的,靜態函數只需保存其函數指針便可,而普通的成員函數還要額外保存一個對象指針,這無疑更麻煩了。 也就是咱們不須要這樣用: ip

 

[cpp]  view plain copy
 
  1. ConcreteCreator<Product, ConcreteProduct> concreteCreator;     
  2. Product* p = concreteCreator.createProduct();  

 

 

只須要這樣寫:get

 

[cpp]  view plain copy
 
  1. Product* p = ConcreteCreator<Product, ConcreteProduct>::createProduct();  

 

   下面是Creator的實現

 

[cpp]  view plain copy
 
  1. // 抽象工廠  
  2. // Product爲抽象產品  
  3. template<typename Product>  
  4. class Creator  
  5. {  
  6.     // 單例實現  
  7. public:  
  8.     static Creator& Instance()  
  9.     {  
  10.         static Creator<Product> instance;  
  11.         return instance;  
  12.     }  
  13. private:  
  14.     Creator() {}  
  15.     ~Creator() {}  
  16.     Creator(Creator&);  
  17.     // 對外接口  
  18. public:  
  19.     typedef Product* (*CreateProductDelegate)( ); // 生產產品的產品 
  20.     typedef std::map<std::string, CreateProductDelegate> MapRegisterCreatorItem;  
  21.     // 根據具體產品生成具體工廠  
  22.     // 並將具體產品註冊進抽象工廠  
  23.     // ConcreteProduct爲具體產品  
  24.     template<typename ConcreteProduct>  
  25.     void registerCreator(const std::string& _type)  
  26.     {  
  27.         mConcreteCreators[_type] = ConcreteCreator<Product, ConcreteProduct>::createProduct;  
  28.     }  
  29.     // 刪除全部具體工廠  
  30.     void unregisterAllCreators()  
  31.     {  
  32.         mConcreteCreators.clear();  
  33.     }  
  34.     // 生產類型爲_type的產品  
  35.     // 失敗返回0  
  36.     Product* createProduct(const std::string& _type)  
  37.     {  
  38.         MapRegisterCreatorItem::iterator type = mConcreteCreators.find(_type);  
  39.         if (type != mConcreteCreators.end())  
  40.         {  
  41.             CreateProductDelegate create = type->second;  
  42.             if (create != 0)  
  43.                 return create();  
  44.         }  
  45.         return 0;  
  46.     }  
  47. private:  
  48.     MapRegisterCreatorItem mConcreteCreators; // 保存全部註冊過的具體產品 
  49. };  

 

下面來簡單解釋一下上面的代碼。

首先Creator實現了單例模式,這只是爲了方便使用,你也能夠不實現爲單例。

Creator裏面保存了全部註冊過的具體工廠,具體工廠在註冊時被構建,每一個具體工廠對應一個名字(string類型)。

createProduct即爲工廠方法,外部經過此接口建立產品,建立時僅需提供具體工廠的名字便可。

咱們以RPG遊戲那個做爲例子。要建立一個PersonCreator,能夠這樣寫

 

[cpp]  view plain copy
 
  1. typedef Creator<Person> PersonCreator;  
  2. PersonCreator& factory = PersonCreator::Instance();  
  3. factory.registerCreator<Person>("Person");  
  4. factory.registerCreator<Hero>("Hero");  
  5. factory.registerCreator<NPC>("NPC");  

 

這樣即完成了註冊過程,你能夠繼續爲其餘類型註冊具體工廠。

要建立一個NPC,能夠這樣寫

 

[cpp]  view plain copy
 
  1. Person* npc = factory.createProduct("NPC");  
[cpp]  view plain copy
 
  1.   

 

3.優缺點

此方法的優勢很明顯,就是用起來很方便。因爲Creator支持不一樣類型,你不要爲不一樣的產品編寫不一樣的Creator。並且其提供了註冊具體工廠的方法,你僅須要寫一行代碼便可爲具體產品生成具體的工廠,而不須要編寫專門的類。

並且其註冊過程是能夠在運行時修改的,也就是說你能夠在運行時動態地註冊或反註冊具體工廠,這樣靈活性就很大了。

缺點的話就是不支持構造函數參數,也就是說在建立產品時不支持參數。固然能夠爲不一樣數量參數編寫具體的模板Creator。但其實我的並不提倡提供無參構造函數。我認爲像這類產品類,都應該提供一個無參的構造函數版本,而後提供getset函數來修改內部成員變量。

相關文章
相關標籤/搜索