一. 工廠方法(factory-method)模式
1. 意圖
定義一個創建對象的接口,讓子類決定實例化哪個產品類。工廠方法使一個對象的創建延遲到子類。
2. 適用性
當一個類不知道它要創建的對象的類時。
當一個類希望由它的子類來決定創建哪個類的對象時。
當一個類決定將創建對象委托給多個子類,并且希望將那個子類是代理這一信息局部化的時候。
3. 結構
4. 參與者
l Creater:
聲明工廠方法的抽象類,工廠方法返回一個產品類(Product)。
可以調用工廠方法返回一個產品對象。
l ConcreteCreater:
重定義工廠方法,以返回一個特定的product。
l Product:
產品抽象類,給用戶提供一致的產品接口。
l ConcreteProduct:
特定的產品,實現product接口。
5. 效果
工廠方法將特定的類的實例化延遲到子類,而且返回product接口,使用戶代碼不用和具體類打交道,一致的對待Product。所以在用戶要加入新產品的時候,無需更改客戶代碼,只需加入一個新的ConcreteProduct和ConcreteCreater即可,這個也是遵 守了“開放封閉原則”。
連接平行的類層次,上面的結構圖中,ConcreteCreater1對應創ConcreterProduct1而ConcreteCreater2對應創建ConcreterProduct2。所以creater和product的類層次是平行的,用戶只需選定一個Creater,就創建出對應product。像是一個map一樣,不會出現牛頭不對馬嘴之態。
6. 實現及變體
Creater有兩種實現,一種就是抽象的工廠方法,具體實現留到子類。另一種就是有一個缺省的實現,子類也可以重新實現這個方法。這種方法使用于真的有一個默認的Product需要實例化的這種情況。
帶參數的工廠方法,這種情況可以創建多種產品,不過有個限制就是所有產品都要實現product接口,否則就失去工廠方法的意義了。代碼如下:
Product* ConcreteCreater1::FactoryMethod(int nID)
{
If(nID == BUTTON)
return new button;
}
Else if(nID == BOX)
return new box;
…
用模板實現,省略創建子類。
class Creater
public:
virtual Product* FactoryMethod() = 0;
};
template<class theProduct>
class TempCreater: public Creater
virtual Product* FactoryMethod();
Product* TempCreater<theProduct>::FactoryMethod()
return new theProduct;
使用這個模版客戶端只需定義產品,而不需定義creater的子類。
二. 程序舉例
在一個ACT游戲中,主角過關過程中有許多敵人,如狼(wolf),蝙蝠(bat),老怪(BOSS),在每一關的剛開始就要創建許多不同的敵人,如果不用工廠方法,則把所有的創建任務都放在了客戶代碼中,則一個代碼不易擴充和修改,二是代碼很雜亂。而用了工廠方法則可以克服這兩個缺點。比如你增加一個新的敵人-恐龍,則只需增加一個恐龍類(ConcreteProduct),再增加一個創建恐龍的類(ConcreteCreater )就OK了。
源碼如下:
三. 相關模式
Abstract Factory經常用工廠方法來實現。
工廠方法通常在Template Methods中被調用。
Prototypes不需要創建Creater的子類。但是,它們通常要求一個針對Product類的Initialize操作。Creater使用Initialize來初始化對象。而Factory Method不需要這樣的操作。
四. 參考文獻
《設計模式精解》 清華大學出版社, 熊杰譯。
《設計模式可復用面向對象軟件的基礎》 機械工業出版社, 四人團著。