工廠對象模式簡介

工廠對象模式簡介

在GoF的《設計模式》一書中,對Factory Method/Object Method 意圖描述以下:ios

定義一個用於建立對象的接口,讓子類決定實例化是哪個類。 Factory Metho是一個類的實例化延遲到其子類。設計模式

其中, 類 Product 定義了一類對象的接口。 ConcreteProduct 實現 Product 的接口。 Creator是工廠方法的包裝器。ConcreteCreator 類實現Creator的接口。基於以上結構,每一個ConcreteProduct必須帶有一個 ConcreteCreator, 用來產生特定的ConcreteProduct。數據結構

這種實現的缺點,在《設計模式》一書中也提到過一點 是客戶可能僅僅想建立一個特定的 ConcreteProduct 對象,但必須額外建立 Creator 的子類。 在ConcreteProduct 的演化上形成額外的工做量。 另外一點從代碼簡潔之道角度來看,每個 ConcreteCreator 的實現都幾乎同樣,就像一幕幕乏味的樣板戲,簡直就是雞肋。ide

那麼如何改進呢?函數

 

用boost factory & boost function實現對象工廠

 

文件:ObjectFactory.h測試

 

  1. #ifndef MP_OBJECT_FACTORY_H  
  2. #define MP_OBJECT_FACTORY_H  
  3. #include <boost/function.hpp>  
  4. #include <map>  
  5.   
  6. /// 工廠模式泛型實現.  
  7. /// 限制: 生成的對象必須爲經過默認構造函數來構造.  
  8. /// 固然你也能夠擴展這個模板讓它支持更多參數的構造函數.  
  9. template<typename IdType, typename ObjectType>  
  10. class ObjectFactory  
  11. {  
  12. public:  
  13.     /// 表示默認構造函數的函數對象.  
  14.     typedef boost::function< ObjectType* () > CreatorType;  
  15.   
  16.     /// 構造函數對應的函數對象的關聯容器.   
  17.     typedef std::map<IdType, CreatorType> ObjectCreator_map;  
  18.   
  19.     /// 註冊子類對象的構造函數信息.  
  20.     void RegisterObjectCreator(const IdType& id, const CreatorType &creator)  
  21.     {  
  22.         objectCreatorMap_[id] = creator;  
  23.     }  
  24.   
  25.     /// 經過默認構造函數在堆上建立一個新的對象實例. 使用new生成.  
  26.     ObjectType * MakeObject(const IdType& id)  
  27.     {  
  28.         ObjectCreator_map::const_iterator iter = objectCreatorMap_.find(id);  
  29.         if (iter == objectCreatorMap_.end())  
  30.         {  
  31.             return NULL;  
  32.         }  
  33.         else  
  34.         {  
  35.             return (iter->second)();  
  36.         }  
  37.     }  
  38.   
  39. private:  
  40.     ObjectCreator_map objectCreatorMap_;  
  41. };  
  42.   
  43. #endif  

 

以上代碼中,模板ObjectFactor接收兩個參數,第一個參數IdType是用來標識是哪一種子類對象的關鍵字。ObjectType是基類對 象類型。也就是上面結構圖中的Product。爲了實現建立ConcreteProduct對象的方法,咱們須要得到每一個子類對象的構造函數信息,經過 RegisterObjectCreator方法咱們將子類對象的構造函數信息保存在工廠中。  那麼哪一種數據結構表示構造函數信息呢? 經過普通函數指針,好像行不通。在這裏咱們用到了 boost::function,它能夠將任意的函數信息封裝到function object對象中,從而能夠實現賦值,調用等操做。設計

以上工廠實現中咱們將任意類型的默認構造函數信息用 boost::function 進行封裝,表示成 typedef boost::function< ObjectType* () > CreatorType;指針

後面咱們就是建一張表來關聯IdType與它所對應ConcreteProduct的構造函數信息。這裏咱們直接用 std::map關聯容器來存儲。對象

RegisterObjectCreator用於註冊ConcreteProduct對象的構造函數信息。接口

MakeObject用於根據傳入的IdType來生成對應的ConcreteProduct對象。注意這一句 (iter->second)(); 它返回指向ObjectType對象的指針。  實際上iter->second返回是一個CreatorType 類型函數對象,對一個函數對象進行()調用。由於CreatorType是對構造函數的封裝,所以其實是調用ConcreteProduct的構造函數 生成一個ConcreteProduct對象。 後面會看到 CreatorType 是咱們用 boost::factory 封裝的,它默認會調用new操做符從堆上構造一個ConcreteProduct對象。

如何使用對象工廠

咱們來實現GoF Factory Method結構圖中相似的代碼。

首先咱們定義幾個類:

Product                  --  產品類接口封裝,定義了類對象的接口。

ConcreteProductA  --  具體的產品A,該類 實現 Product 的接口。

ConcreteProductB  --  具體的產品B,該類 實現 Product 的接口。

文件:Product.h

  1. #ifndef MP_PRODUCT_H  
  2. #define MP_PRODUCT_H  
  3. #include <boost/shared_ptr.hpp>  
  4.   
  5. class Product  
  6. {  
  7. public:  
  8.     explicit Product() {};  
  9.     virtual ~Product() {};  
  10.     virtual void DoSomething() = 0;  
  11. };  
  12.   
  13. typedef boost::shared_ptr<Product> Product_ptr;  
  14.   
  15. #endif  

文件:ConcreteProductA.h

  1. #ifndef MP_CONCRETE_PRODUCT_A_H  
  2. #define MP_CONCRETE_PRODUCT_A_H  
  3. #include <iostream>  
  4.   
  5. class ConcreteProductA  
  6.     :public Product  
  7. {  
  8. public:  
  9.     void DoSomething()  
  10.     {  
  11.         std::cout<<__FUNCTION__<<std::endl;  
  12.     }  
  13. };  
  14.   
  15.   
  16. #endif  

文件:ConcreteProductB.h

  1. #ifndef MP_CONCRETE_PRODUCT_B_H  
  2. #define MP_CONCRETE_PRODUCT_B_H  
  3. #include <iostream>  
  4.   
  5. class ConcreteProductB  
  6.     :public Product  
  7. {  
  8. public:  
  9.     void DoSomething()  
  10.     {  
  11.         std::cout<<__FUNCTION__<<std::endl;  
  12.     }  
  13. };  
  14.   
  15.   
  16. #endif 

 

下面咱們來測試上面的對象工廠。

文件: Main.cpp

  1. #include "Product.h"  
  2. #include "ConcreteProductA.h"  
  3. #include "ConcreteProductB.h"  
  4. #include "ObjectFactory.h"  
  5. #include <string>  
  6. #include <boost/functional/factory.hpp>  
  7.   
  8.   
  9. int main(int argc, char **argv)  
  10. {  
  11.     ObjectFactory<std::string, Product> productFactory; // 對象工廠  
  12.      
  13.     // 註冊對象構造器.  
  14.     productFactory.RegisterObjectCreator("PRODUCT_A", boost::factory<ConcreteProductA *>() );  
  15.     productFactory.RegisterObjectCreator("PRODUCT_B", boost::factory<ConcreteProductB *>() );  
  16.   
  17.     //經過工廠生成對象, 存儲在shared_ptr中.  
  18.     Product_ptr productA( productFactory.MakeObject("PRODUCT_A") );  
  19.     Product_ptr productB( productFactory.MakeObject("PRODUCT_B") );  
  20.   
  21.     // 演示多態性質。  
  22.     productA->DoSomething();  
  23.     productB->DoSomething();  
  24.     return 0;  
  25. }  

 

在以上測試中,咱們首先生成一個對象工廠,這裏咱們以std::string做爲IdType來標示是哪一種類型的ConcreteProduct。

而後向工廠中註冊具體類的構造方法: productFactory.RegisterObjectCreator("PRODUCT_A", boost::factory<ConcreteProductA *>() ); 注意:這裏用到了boost::factory,它能夠將 new 表達式封裝成函數對象(function object),  這也正式咱們工廠的註冊方法所須要的參數。

後面咱們調用對象工廠的MakeObject來生成咱們指望的ConcreteProduct對象。 咱們用一個字符串來標識要生成哪一種類型的ConcreteProduct對象。同時咱們將返回的對象指針保存在 shared_ptr中,從而實現對象的自動管理。 類型Product_ptr的定義爲: typedef boost::shared_ptr<Product> Product_ptr;  它是對Product接口的智能指針封裝。

最後,就是展現多態行爲的時候了,咱們調用不一樣ConcreteProduct對象的DoSomething來演示。

限制說明:

1. 本文只是實現了帶有默認構造函數的對象工廠。 若是你願意也能夠實現帶有多個參數構造函數的對象工廠。

2. ObjectFactory 也能夠實現爲Singleton模式,根據我的須要吧,本文的重點不在這裏。

 

參考資料:

1.  《設計模式可複用面向對象軟件的基礎》/ Design Patterns:Elements of Reusable Object-Oriented software  GoF

2. 《C++_設計新思惟》 / Modern C++ Design    Andrei Alexandrescu

3.  Boost.Functional/Factory document             Tobias Schwinger

4. Boost.Function document                              Douglas Gregor

相關文章
相關標籤/搜索