在GoF的《設計模式》一書中,對Factory Method/Object Method 意圖描述以下:ios
定義一個用於建立對象的接口,讓子類決定實例化是哪個類。 Factory Metho是一個類的實例化延遲到其子類。設計模式
其中, 類 Product 定義了一類對象的接口。 ConcreteProduct 實現 Product 的接口。 Creator是工廠方法的包裝器。ConcreteCreator 類實現Creator的接口。基於以上結構,每一個ConcreteProduct必須帶有一個 ConcreteCreator, 用來產生特定的ConcreteProduct。數據結構
這種實現的缺點,在《設計模式》一書中也提到過一點 是客戶可能僅僅想建立一個特定的 ConcreteProduct 對象,但必須額外建立 Creator 的子類。 在ConcreteProduct 的演化上形成額外的工做量。 另外一點從代碼簡潔之道角度來看,每個 ConcreteCreator 的實現都幾乎同樣,就像一幕幕乏味的樣板戲,簡直就是雞肋。ide
那麼如何改進呢?函數
文件:ObjectFactory.h測試
以上代碼中,模板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
文件:ConcreteProductA.h
文件:ConcreteProductB.h
下面咱們來測試上面的對象工廠。
文件: Main.cpp
在以上測試中,咱們首先生成一個對象工廠,這裏咱們以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