工廠物件模式簡介

2021-09-25 13:18:56 字數 4000 閱讀 8468

在gof的《設計模式》一書中,對factory method/object method 意圖描述如下:

定義乙個用於建立物件的介面,讓子類決定例項化是哪乙個類。 factory metho是乙個類的例項化延遲到其子類。

其結構圖如下:

其中, 類 product 定義了一類物件的介面。 concreteproduct 實現 product 的介面。 creator是工廠方法的包裝器。concretecreator 類實現creator的介面。基於以上結構,每個concreteproduct必須帶有乙個 concretecreator, 用來產生特定的concreteproduct。

這種實現的缺點,在《設計模式》一書中也提到過一點 是客戶可能僅僅想建立乙個特定的 concreteproduct 物件,但必須額外建立 creator 的子類。 在concreteproduct 的演化上造成額外的工作量。 另一點從**簡潔之道角度來看,每乙個 concretecreator 的實現都幾乎一樣,就像一幕幕乏味的樣板戲,簡直就是雞肋。

那麼如何改進呢?

檔案:objectfactory.h

[cpp]view plain

copy

#ifndef mp_object_factory_h  

#define mp_object_factory_h  

#include 

#include 

/// 工廠模式泛型實現.  

/// 限制: 生成的物件必須為通過預設建構函式來構造.  

/// 當然你也可以擴充套件這個模板讓它支援更多引數的建構函式.  

template  

class objectfactory  

/// 通過預設建構函式在堆上建立乙個新的物件例項. 使用new生成.  

objecttype * makeobject(const idtype& id)  

else  

}  private:  

objectcreator_map objectcreatormap_;  

};  

#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

[cpp]view plain

copy

#ifndef mp_product_h  

#define mp_product_h  

#include 

class product  

;  virtual ~product() {};  

virtual void dosomething() = 0;  

};  

typedef boost::shared_ptrproduct_ptr;  

#endif  

檔案:concreteproducta.h

[cpp]view plain

copy

#ifndef mp_concrete_product_a_h  

#define mp_concrete_product_a_h  

#include 

class concreteproducta  

:public product  

};  

#endif  

檔案:concreteproductb.h

[cpp]view plain

copy

#ifndef mp_concrete_product_b_h  

#define mp_concrete_product_b_h  

#include 

class concreteproductb  

:public product  

};  

#endif  

下面我們來測試上面的物件工廠。

檔案: main.cpp

[cpp]view plain

copy

#include "product.h"  

#include "concreteproducta.h"  

#include "concreteproductb.h"  

#include "objectfactory.h"  

#include 

#include 

int main(int argc, char **ar**)    

在以上測試中,我們首先生成乙個物件工廠,這裡我們以std::string作為idtype來標示是哪種型別的concreteproduct。

然後向工廠中註冊具體類的構造方法: productfactory.registerobjectcreator("product_a", boost::factory() ); 注意:這裡用到了boost::factory,它可以將 new 表示式封裝成函式物件(function object),  這也正式我們工廠的註冊方法所需要的引數。

後面我們呼叫物件工廠的makeobject來生成我們期望的concreteproduct物件。 我們用乙個字串來標識要生成哪種型別的concreteproduct物件。同時我們將返回的物件指標儲存在 shared_ptr中,從而實現物件的自動管理。 型別product_ptr的定義為: typedef boost::shared_ptrproduct_ptr;  它是對product介面的智慧型指標封裝。

最後,就是展示多型行為的時候了,我們呼叫不同concreteproduct物件的dosomething來演示。執行效果如下:

1. 本文只是實現了帶有預設建構函式的物件工廠。 如果你願意也可以實現帶有多個引數建構函式的物件工廠。

2. objectfactory 也可以實現為singleton模式,根據個人需要吧,本文的重點不在這裡。

工廠物件模式簡介

在gof的 設計模式 一書中,對factory method object method 意圖描述如下 定義乙個用於建立物件的介面,讓子類決定例項化是哪乙個類。factory metho是乙個類的例項化延遲到其子類。其結構圖如下 其中,類 product 定義了一類物件的介面。concretepro...

工廠物件模式簡介

在gof的 設計模式 一書中,對factory method object method 意圖描述如下 定義乙個用於建立物件的介面,讓子類決定例項化是哪乙個類。factory metho是乙個類的例項化延遲到其子類。其結構圖如下 其中,類 product 定義了一類物件的介面。concretepro...

工廠模式簡介

簡介 工廠模式 專門負責有大量公共介面的類。它可以動態地決定哪乙個類例項化,而不必事先知道要例項化那個類。客戶類和工廠類是分開的。當然工廠模式也存在著缺點 當產品修改時,工廠類也要做出相應的改變。工廠模式的作用 系統可以在不修改具體工廠角色的情況下引進新的產品 客戶端不必關心物件的建立,把物件的建立...