問題描述
之前講到了C++設計模式——簡單工廠模式,由於簡單工廠模式的局限性,比如:工廠現在能生產ProductA、ProductB和ProductC三種產品了,此時,需要增加生產ProductD產品;那么,首先是不是需要在產品枚舉類型中添加新的產品類型標識,然后,修改Factory類中的switch結構代碼。是的,這種對代碼的修改,對原有代碼的改動量較大,易產生編碼上的錯誤(雖然很簡單,如果工程大了,出錯也是在所難免的!!!)。這種對代碼的修改是最原始,最野蠻的修改,本質上不能稱之為對代碼的擴展。同時,由於對已經存在的函數進行了修改,那么以前進行過的測試,都將是無效的,所有的測試,都將需要重新進行,所有的代碼都需要進行重新覆蓋。這種,增加成本,不能提高效率的事情,在公司是絕對不允許的(除非昏庸的PM)。出於種種原因,簡單工廠模式,在實際項目中使用的較少。那么該怎么辦?怎么辦呢?需要對原有代碼影響降到最小,同時能對原有功能進行擴展。
UML類圖
那么今天介紹的工廠方法模式,就隆重登場了。它只是對簡單工廠模式的擴展,在GOF的介紹中,它們是合並在一起的,而我則是單獨分開進行講解的,就是為了區分二者的利弊,便於大家在實際項目中進行更好的把握與應用。工廠方法模式是在簡單工廠模式的基礎上,對“工廠”添加了一個抽象層。將工廠共同的動作抽象出來,作為抽象類,而具體的行為由子類本身去實現,讓子類去決定生產什么樣的產品。

如圖,FactoryA專心負責生產ProductA,FactoryB專心負責生產ProductB,FactoryA和FactoryB之間沒有關系;如果到了后期,如果需要生產ProductC時,我們則可以創建一個FactoryC工廠類,該類專心負責生產ProductC類產品。由於FactoryA、FactoryB和FactoryC之間沒有關系,當加入FactoryC加入時,對FactoryA和FactoryB的工作沒有產生任何影響,那么對代碼進行測試時,只需要單獨對FactoryC和ProductC進行單元測試,而FactoryA和FactoryB則不用進行測試,則可省去大量無趣無味的測試工作。
適用場合
工廠方法模式的意義是定義一個創建產品對象的工廠接口,將實際創建工作推遲到子類當中。核心工廠類不再負責產品的創建,這樣核心類成為一個抽象工廠角色,僅負責具體工廠子類必須實現的接口,這樣進一步抽象化的好處是使得工廠方法模式可以使系統在不修改具體工廠角色的情況下引進新的產品。
- 在設計的初期,就考慮到產品在后期會進行擴展的情況下,可以使用工廠方法模式;
- 產品結構較復雜的情況下,可以使用工廠方法模式;
由於使用設計模式是在詳細設計時,就需要進行定奪的,所以,需要權衡多方面的因素,而不能為了使用設計模式而使用設計模式。
代碼實現
1 #include <iostream> 2 using namespace std; 3 4 class Product 5 { 6 public: 7 virtual void Show() = 0; 8 }; 9 10 class ProductA : public Product 11 { 12 public: 13 void Show() 14 { 15 cout<< "I'm ProductA"<<endl; 16 } 17 }; 18 19 class ProductB : public Product 20 { 21 public: 22 void Show() 23 { 24 cout<< "I'm ProductB"<<endl; 25 } 26 }; 27 28 class Factory 29 { 30 public: 31 virtual Product *CreateProduct() = 0; 32 }; 33 34 class FactoryA : public Factory 35 { 36 public: 37 Product *CreateProduct() 38 { 39 return new ProductA (); 40 } 41 }; 42 43 class FactoryB : public Factory 44 { 45 public: 46 Product *CreateProduct() 47 { 48 return new ProductB (); 49 } 50 }; 51 52 int main(int argc , char *argv []) 53 { 54 Factory *factoryA = new FactoryA (); 55 Product *productA = factoryA->CreateProduct(); 56 productA->Show(); 57 58 Factory *factoryB = new FactoryB (); 59 Product *productB = factoryB->CreateProduct(); 60 productB->Show(); 61 62 if (factoryA != NULL) 63 { 64 delete factoryA; 65 factoryA = NULL; 66 } 67 68 if (productA != NULL) 69 { 70 delete productA; 71 productA = NULL; 72 } 73 74 if (factoryB != NULL) 75 { 76 delete factoryB; 77 factoryB = NULL; 78 } 79 80 if (productB != NULL) 81 { 82 delete productB; 83 productB = NULL; 84 } 85 return 0; 86 }
