簡單工廠模式本應該放到工廠模式那篇博客中去介紹的,因為與策略模式有一定的相似性,這里摘出來單獨成章。
簡單工廠模式
用一個單獨的類來做創造實例的過程,就是工廠。
工廠模式有一種非常形象的描述:建立對象的類就如一個工廠,而需要被建立的對象就是一個個產品;在工廠中加工產品,使用產品的人,不用在乎產品是如何生產出來的。從軟件開發的角度來說,這樣就有效的降低了模塊之間的耦合。
適用場合
在程序中,需要創建的對象很多,導致對象的new操作多且雜時,需要使用簡單工廠模式;
由於對象的創建過程是我們不需要去關心的,而我們注重的是對象的實際操作,所以,我們需要分離對象的創建和操作兩部分,如此,方便后期的程序擴展和維護。
基本代碼
typedef enum ProductTypeTag { TypeA, TypeB, TypeC } PRODUCTTYPE; class Product { public: virtual void Show() = 0; }; class ProductA : public Product { public: void Show() { cout<<"I'm ProductA"<<endl; } }; class ProductB : public Product { public: void Show() { cout<<"I'm ProductB"<<endl; } }; class ProductC : public Product { public: void Show() { cout<<"I'm ProductC"<<endl; } }; class Factory { public: Product* CreateProduct(PRODUCTTYPE type) { switch (type) { case TypeA: return new ProductA(); case TypeB: return new ProductB(); case TypeC: return new ProductC(); default: return NULL; } } }; int main(int argc, char *argv[]) { Factory *ProductFactory = new Factory(); Product *productObjA = ProductFactory->CreateProduct(TypeA); if (productObjA != NULL) productObjA->Show(); Product *productObjB = ProductFactory->CreateProduct(TypeB); if (productObjB != NULL) productObjB->Show(); Product *productObjC = ProductFactory->CreateProduct(TypeC); if (productObjC != NULL) productObjC->Show(); return 0; }
簡單工廠模式的局限性
若工廠現在能生產ProductA、ProductB和ProductC三種產品了,此時,需要增加生產ProductD產品;那么,首先是不是需要在產品枚舉類型中添加新的產品類型標識,然后,修改Factory類中的switch結構代碼。是的,這種對代碼的修改,對原有代碼的改動量較大,易產生編碼上的錯誤(雖然很簡單,如果工程大了,出錯也是在所難免的!!!)。同時,由於對已經存在的函數進行了修改,那么以前進行過的測試,都將是無效的,所有的測試,都將需要重新進行,所有的代碼都需要進行重新覆蓋。
工廠模式的引入
FactoryA專心負責生產ProductA,FactoryB專心負責生產ProductB,FactoryA和FactoryB之間沒有關系;如果到了后期,如果需要生產ProductC時,我們則可以創建一個FactoryC工廠類,該類專心負責生產ProductC類產品。由於FactoryA、FactoryB和FactoryC之間沒有關系,當加入FactoryC加入時,對FactoryA和FactoryB的工作沒有產生任何影響,那么對代碼進行測試時,只需要單獨對FactoryC和ProductC進行單元測試,而FactoryA和FactoryB則不用進行測試,可省去大量無趣無味的測試工作。
class Product { public: virtual void Show() = 0; }; class ProductA : public Product { public: void Show() { cout<< "I'm ProductA"<<endl; } }; class ProductB : public Product { public: void Show() { cout<< "I'm ProductB"<<endl; } }; class Factory { public: virtual Product *CreateProduct() = 0; }; class FactoryA : public Factory { public: Product *CreateProduct() { return new ProductA (); } }; class FactoryB : public Factory { public: Product *CreateProduct() { return new ProductB (); } }; int main(int argc, char *argv []) { Factory *factoryA = new FactoryA (); Product *productA = factoryA->CreateProduct(); productA->Show(); Factory *factoryB = new FactoryB (); Product *productB = factoryB->CreateProduct(); productB->Show(); return 0; }
詳細內容參見上一篇博客C++設計模式——工廠模式Factory Method
簡單工廠類:
public class OperationFactory { public static Operation CreateOperate (string operate) { Operation oper=null; switch (operate) { case "+": oper = new OperationAdd(); break; case "-": oper = new OperationSub(); break; case "*": oper = new OperationMul(); break; case "/": oper = new OperationDiv(); break; default: oper = new Operation(); break; } return oper; } }
策略模式中的Context類:
class Context { CashSuper csuper; public Context(CashSuper cs) { this.csuper = cs; } public double GetResult(double money) { //調用具體策略類的收費方法 return csuper.acceptCash(money); } }
1.首先看一下接收的參數:簡單工廠類中的 CreateOperate 方法接收的是字符串,返回的是一個 Operation 對象;而 Context 類初始化時需要接收一個 CashSuper 對象。
2.簡單工廠類中是根據接收的條件創建一個相應的對象,而 Context 類接收的是一個對象,可以調用方法去執行此對象的方法。
總結簡單工廠模式和策略模式
1.從類型上說:簡單工廠模式屬於創建型模式,而策略模式屬於行為型模式。
2.接下來,看一個小例子:
斧子有很多種,有一個工廠專門負責生產各種需求的斧子。
工廠模式:
1)根據你給出的目的來生產不同用途的斧子,例如要砍人,那么工廠生產砍人斧子,要伐木就生產伐木斧子。
2)即根據你給出一些屬性來生產不同行為的一類對象返回給你。
3)關注對象創建
策略模式:
1)用工廠生產的斧子來做對應的事情,例如用砍人的斧子來砍人,用伐木的斧子來伐木。
2)即根據你給出對應的對象來執行對應的方法。
3)關注行為的選擇
3.簡單工廠模式:根據客戶選擇的條件,來幫客戶創建一個對象。
策略模式:客戶給它一個創建好的對象,它來幫客戶做相應的事。
兩種模式的優缺點
首先來看一下兩種模式的客戶端代碼:
//簡單工廠模式的客戶端: Operation op; //交給簡單工廠類創建對象 op = OperationFactory.CreateOperate("+"); op.StrNumberA = 10; op.StrNumberB = 20; //調用生成對象的方法 double result = op.GetResult(); Console.WriteLine(result);
//策略模式的客戶端: double total = 0; private void btnOk_Click(object sender, EventArgs e) { CashContext cc = null; //客戶端自己創建對象 switch(cbxType.SelectedItem.ToString()) { case: "正常收費": cc = new CashContext(new CashNormal()); break; case: "滿300返100": cc = new CashContext(new CashReturn()); break; case: "打8折": cc = new CashContext(new CashRebate()); break; } //計算具體策略收取的費用,交給context類執行相應的方法,客戶端只需要接收返回的值就可以 double acceptMoney = cc.GetResult(Convert.ToDouble(txtPrice.Text) * Convert.ToDouble(txtNum.Text)); //計算總費用 total += acceptMoney; listBox1.Items.Add("單價:" + txtPrice.Text + " 數量:" + txtNum.Text + " " + comboBox1.SelectedItem.ToString() + "總計:" + acceptMoney); lblResult.Text = total.ToString(); }
通過比較客戶端的代碼發現:
簡單工廠模式:將對象的選擇創建交給了簡單工廠類,客戶端只需要輸入相應的條件就可以,不用負責對象的創建,但是需要客戶端自己調用算法類的方法。但是一旦需要增加新的運算類,比如開根運算,就要去修改簡單工廠類。
策略模式:對象的選擇創建仍需要自己來做,但是將調用方法的職責交給了Context類。一旦需要增加新的策略需要修改客戶端。
因此,簡單工廠模式的缺點就是當有新的需求增加時,需要頻繁的修改工廠類。只用策略模式,當有新的需求增加時需要修改的是客戶端,客戶端仍然承擔着創建對象的職責,並沒有減輕客戶端的壓力。而將這兩種模式結合起來使用,則需要修改 Context 類,總之不是完美的。