工廠模式屬於建立型模式,大體能夠分爲三類,簡單工廠模式、工廠方法模式、抽象工廠模式。ios
經過兩個例子講解這三種工廠模式windows
首先介紹簡單工廠模式,它的主要特色是須要在工廠類中作判斷,從而創造相應的產品。當增長新的產品時,就須要修改工廠類。有點抽象,舉個例子就明白了。有一家生產處理器核的廠家,它只有一個工廠,可以生產兩種型號的處理器核。客戶須要什麼樣的處理器核,必定要顯示地告訴生產工廠。下面給出一種實現方案。設計模式
1 enum CTYPE {COREA, COREB}; 2 class SingleCore 3 { 4 public: 5 virtual void Show() = 0; 6 }; 7 //單核A 8 class SingleCoreA: public SingleCore 9 { 10 public: 11 void Show() { cout<<"SingleCore A"<<endl; } 12 }; 13 //單核B 14 class SingleCoreB: public SingleCore 15 { 16 public: 17 void Show() { cout<<"SingleCore B"<<endl; } 18 }; 19 //惟一的工廠,能夠生產兩種型號的處理器核,在內部判斷 20 class Factory 21 { 22 public: 23 SingleCore* CreateSingleCore(enum CTYPE ctype) 24 { 25 if(ctype == COREA) //工廠內部判斷 26 return new SingleCoreA(); //生產核A 27 else if(ctype == COREB) 28 return new SingleCoreB(); //生產核B 29 else 30 return NULL; 31 } 32 };
這樣設計的主要缺點以前也提到過,就是要增長新的核類型時,就須要修改工廠類。這就違反了開放封閉原則:軟件實體(類、模塊、函數)能夠擴展,可是不可修改。因而,工廠方法模式出現了。所謂工廠方法模式,是指定義一個用於建立對象的接口,讓子類決定實例化哪個類。Factory Method使一個類的實例化延遲到其子類。函數
聽起來很抽象,仍是以剛纔的例子解釋。這家生產處理器核的產家賺了很多錢,因而決定再開設一個工廠專門用來生產B型號的單核,而原來的工廠專門用來生產A型號的單核。這時,客戶要作的是找好工廠,好比要A型號的核,就找A工廠要;不然找B工廠要,再也不須要告訴工廠具體要什麼型號的處理器核了。下面給出一個實現方案。測試
1 class SingleCore 2 { 3 public: 4 virtual void Show() = 0; 5 }; 6 //單核A 7 class SingleCoreA: public SingleCore 8 { 9 public: 10 void Show() { cout<<"SingleCore A"<<endl; } 11 }; 12 //單核B 13 class SingleCoreB: public SingleCore 14 { 15 public: 16 void Show() { cout<<"SingleCore B"<<endl; } 17 }; 18 class Factory 19 { 20 public: 21 virtual SingleCore* CreateSingleCore() = 0; 22 }; 23 //生產A核的工廠 24 class FactoryA: public Factory 25 { 26 public: 27 SingleCoreA* CreateSingleCore() { return new SingleCoreA; } 28 }; 29 //生產B核的工廠 30 class FactoryB: public Factory 31 { 32 public: 33 SingleCoreB* CreateSingleCore() { return new SingleCoreB; } 34 };
工廠方法模式也有缺點,每增長一種產品,就須要增長一個對象的工廠。若是這家公司發展迅速,推出了不少新的處理器核,那麼就要開設相應的新工廠。在C++實現中,就是要定義一個個的工廠類。顯然,相比簡單工廠模式,工廠方法模式須要更多的類定義。編碼
既然有了簡單工廠模式和工廠方法模式,爲何還要有抽象工廠模式呢?它到底有什麼做用呢?仍是舉這個例子,這家公司的技術不斷進步,不只能夠生產單核處理器,也能生產多核處理器。如今簡單工廠模式和工廠方法模式都鞭長莫及。抽象工廠模式登場了。它的定義爲提供一個建立一系列相關或相互依賴對象的接口,而無需指定它們具體的類。具體這樣應用,這家公司仍是開設兩個工廠,一個專門用來生產A型號的單核多核處理器,而另外一個工廠專門用來生產B型號的單核多核處理器,下面給出實現的代碼。spa
1 //單核 2 class SingleCore 3 { 4 public: 5 virtual void Show() = 0; 6 }; 7 class SingleCoreA: public SingleCore 8 { 9 public: 10 void Show() { cout<<"Single Core A"<<endl; } 11 }; 12 class SingleCoreB :public SingleCore 13 { 14 public: 15 void Show() { cout<<"Single Core B"<<endl; } 16 }; 17 //多核 18 class MultiCore 19 { 20 public: 21 virtual void Show() = 0; 22 }; 23 class MultiCoreA : public MultiCore 24 { 25 public: 26 void Show() { cout<<"Multi Core A"<<endl; } 27 28 }; 29 class MultiCoreB : public MultiCore 30 { 31 public: 32 void Show() { cout<<"Multi Core B"<<endl; } 33 }; 34 //工廠 35 class CoreFactory 36 { 37 public: 38 virtual SingleCore* CreateSingleCore() = 0; 39 virtual MultiCore* CreateMultiCore() = 0; 40 }; 41 //工廠A,專門用來生產A型號的處理器 42 class FactoryA :public CoreFactory 43 { 44 public: 45 SingleCore* CreateSingleCore() { return new SingleCoreA(); } 46 MultiCore* CreateMultiCore() { return new MultiCoreA(); } 47 }; 48 //工廠B,專門用來生產B型號的處理器 49 class FactoryB : public CoreFactory 50 { 51 public: 52 SingleCore* CreateSingleCore() { return new SingleCoreB(); } 53 MultiCore* CreateMultiCore() { return new MultiCoreB(); } 54 };
以前在公司作了一個windows 8平臺的閱讀器。首先,須要將電子書中的內容渲染到屏幕上,而電子書每一頁都包含各類各樣的內容,好比:圖形、圖像和文字等等;不一樣的內容,就是不一樣的對象;在將不一樣的內容渲染到屏幕上以前,就須要new操做,創建不一樣的對象,而後再在屏幕上進行描繪。這個時候,就須要進行不少new操做,new操做分佈在代碼的不一樣地方,管理起來很麻煩,並且也很亂,到後期擴展和維護的時候,有的時候,對象多的讓開發人員不知道這個對象是幹什麼的,這就增長了難度;同時,new操做,都會有對應的異常處理,最後,就會發現,在代碼中,new了一個對象,而後,就跟着一段異常處理代碼,這時編碼變的極其混亂和臃腫。那麼怎麼辦?怎麼辦?此時,咱們須要一個新的類,專門從事對象的創建和釋放,以後,對象的各類操做,和這個類沒有任何關係。這個專門創建對象的類,向外暴漏建立對象的接口,供外部調用。.net
工廠模式有一種很是形象的描述,創建對象的類就如一個工廠,而須要被創建的對象就是一個個產品;在工廠中加工產品,使用產品的人,不用在意產品是如何生產出來的。從軟件開發的角度來講,這樣就有效的下降了模塊之間的耦合。設計
1 #include <iostream> 2 #include <vector> 3 using namespace std; 4 5 typedef enum ProductTypeTag 6 { 7 TypeA, 8 TypeB, 9 TypeC 10 }PRODUCTTYPE; 11 12 // Here is the product class 13 class Product 14 { 15 public: 16 virtual void Show() = 0; 17 }; 18 19 class ProductA : public Product 20 { 21 public: 22 void Show() 23 { 24 cout<<"I'm ProductA"<<endl; 25 } 26 }; 27 28 class ProductB : public Product 29 { 30 public: 31 void Show() 32 { 33 cout<<"I'm ProductB"<<endl; 34 } 35 }; 36 37 class ProductC : public Product 38 { 39 public: 40 void Show() 41 { 42 cout<<"I'm ProductC"<<endl; 43 } 44 }; 45 46 // Here is the Factory class 47 class Factory 48 { 49 public: 50 Product* CreateProduct(PRODUCTTYPE type) 51 { 52 switch (type) 53 { 54 case TypeA: 55 return new ProductA(); 56 57 case TypeB: 58 return new ProductB(); 59 60 case TypeC: 61 return new ProductC(); 62 63 default: 64 return NULL; 65 } 66 } 67 }; 68 69 int main(int argc, char *argv[]) 70 { 71 // First, create a factory object 72 Factory *ProductFactory = new Factory(); 73 Product *productObjA = ProductFactory->CreateProduct(TypeA); 74 if (productObjA != NULL) 75 productObjA->Show(); 76 77 Product *productObjB = ProductFactory->CreateProduct(TypeB); 78 if (productObjB != NULL) 79 productObjB->Show(); 80 81 Product *productObjC = ProductFactory->CreateProduct(TypeC); 82 if (productObjC != NULL) 83 productObjC->Show(); 84 85 delete ProductFactory; 86 ProductFactory = NULL; 87 88 delete productObjA; 89 productObjA = NULL; 90 91 delete productObjB; 92 productObjB = NULL; 93 94 delete productObjC; 95 productObjC = NULL; 96 97 return 0; 98 }
因爲簡單工廠模式的侷限性,好比:工廠如今能生產ProductA、ProductB和ProductC三種產品了,此時,須要增長生產ProductD產品;那麼,首先是否是須要在產品枚舉類型中添加新的產品類型標識,而後,修改Factory類中的switch結構代碼。是的,這種對代碼的修改,對原有代碼的改動量較大,易產生編碼上的錯誤(雖然很簡單,若是工程大了,出錯也是在所不免的!!!)。這種對代碼的修改是最原始,最野蠻的修改,本質上不能稱之爲對代碼的擴展。同時,因爲對已經存在的函數進行了修改,那麼之前進行過的測試,都將是無效的,全部的測試,都將須要從新進行,全部的代碼都須要進行從新覆蓋。這種,增長成本,不能提升效率的事情,在公司是絕對不容許的(除非昏庸的PM)。出於種種緣由,簡單工廠模式,在實際項目中使用的較少。那麼該怎麼辦?怎麼辦呢?須要對原有代碼影響降到最小,同時能對原有功能進行擴展。3d
工廠方法模式的意義是定義一個建立產品對象的工廠接口,將實際建立工做推遲到子類當中。核心工廠類再也不負責產品的建立,這樣核心類成爲一個抽象工廠角色,僅負責具體工廠子類必須實現的接口,這樣進一步抽象化的好處是使得工廠方法模式可使系統在不修改具體工廠角色的狀況下引進新的產品。
因爲使用設計模式是在詳細設計時,就須要進行定奪的,因此,須要權衡多方面的因素,而不能爲了使用設計模式而使用設計模式。
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 }
因爲工廠方法模式建立的對象都是繼承於Product的,因此工廠方法模式中,每一個工廠只能建立單一種類的產品,當須要生產一種全新的產品(不繼承自Product)時,發現工廠方法是愛莫能助。
舉個例子來講:一個顯示器電路板廠商,旗下的顯示器電路板種類有非液晶的和液晶的;這個時候,廠商建造兩個工廠,工廠A負責生產非液晶顯示器電路板,工廠B負責生產液晶顯示器電路板;工廠一直就這樣運行着。有一天,總經理髮現,直接生產顯示器的其他部分也挺掙錢,因此,總經理決定,再創建兩個工廠C和D;C負責生產非液晶顯示器的其他部件,D負責生產液晶顯示器的其他部件。此時,旁邊參謀的人就說了,經理,這樣作很差,咱們能夠直接在工廠A中添加一條負責生產非液晶顯示器的其他部件的生產線,在工廠B中添加一條生產液晶顯示器的其他部件的生產線,這樣就能夠不用增長廠房,只用將現有廠房進行擴大一下,同時也方便工廠的管理,並且生產非液晶顯示器電路板的技術人員對非液晶顯示的其他部件的生產具備指導的做用,生產液晶顯示器電路板也是同理。總經理髮現這是一個不錯的主意。
再回到軟件開發的過程當中來,工廠A和B就是以前所說的工廠方法模式;總經理再次創建工廠C和D,就是重複工廠方法模式,只是生產的產品不一樣罷了。這樣作的弊端就如參謀所說的那樣,增長了管理成本和人力成本。在面向對象開發的過程當中,是很注重對象管理和維護的,對象越多,就越難進行管理和維護;若是工廠數量過多,那麼管理和維護的成本將大大增長;雖然生產的是不一樣的產品,可是能夠兩者之間是有微妙的關係的,如參謀所說,技術人員的一些技術經驗是能夠借鑑的,這就至關於同一個類中的不一樣對象,之間是能夠公用某些資源的。那麼,增長一條流水線,擴大廠房,固然是最好的主意了。
實際問題已經獲得瞭解決,那麼如何使用設計模式模擬這個實際的問題呢?那就是接下來所說的抽象工廠模式。
工廠方法模式適用於產品種類結構單一的場合,爲一類產品提供建立的接口;而抽象工廠方法適用於產品種類結構多的場合,主要用於建立一組(有多個種類)相關的產品,爲它們提供建立的接口;就是當具備多個抽象角色時,抽象工廠即可以派上用場。
1 #include <iostream> 2 using namespace std; 3 4 // Product A 5 class ProductA 6 { 7 public: 8 virtual void Show() = 0; 9 }; 10 11 class ProductA1 : public ProductA 12 { 13 public: 14 void Show() 15 { 16 cout<<"I'm ProductA1"<<endl; 17 } 18 }; 19 20 class ProductA2 : public ProductA 21 { 22 public: 23 void Show() 24 { 25 cout<<"I'm ProductA2"<<endl; 26 } 27 }; 28 29 // Product B 30 class ProductB 31 { 32 public: 33 virtual void Show() = 0; 34 }; 35 36 class ProductB1 : public ProductB 37 { 38 public: 39 void Show() 40 { 41 cout<<"I'm ProductB1"<<endl; 42 } 43 }; 44 45 class ProductB2 : public ProductB 46 { 47 public: 48 void Show() 49 { 50 cout<<"I'm ProductB2"<<endl; 51 } 52 }; 53 54 // Factory 55 class Factory 56 { 57 public: 58 virtual ProductA *CreateProductA() = 0; 59 virtual ProductB *CreateProductB() = 0; 60 }; 61 62 class Factory1 : public Factory 63 { 64 public: 65 ProductA *CreateProductA() 66 { 67 return new ProductA1(); 68 } 69 70 ProductB *CreateProductB() 71 { 72 return new ProductB1(); 73 } 74 }; 75 76 class Factory2 : public Factory 77 { 78 ProductA *CreateProductA() 79 { 80 return new ProductA2(); 81 } 82 83 ProductB *CreateProductB() 84 { 85 return new ProductB2(); 86 } 87 }; 88 89 int main(int argc, char *argv[]) 90 { 91 Factory *factoryObj1 = new Factory1(); 92 ProductA *productObjA1 = factoryObj1->CreateProductA(); 93 ProductB *productObjB1 = factoryObj1->CreateProductB(); 94 95 productObjA1->Show(); 96 productObjB1->Show(); 97 98 Factory *factoryObj2 = new Factory2(); 99 ProductA *productObjA2 = factoryObj2->CreateProductA(); 100 ProductB *productObjB2 = factoryObj2->CreateProductB(); 101 102 productObjA2->Show(); 103 productObjB2->Show(); 104 105 if (factoryObj1 != NULL) 106 { 107 delete factoryObj1; 108 factoryObj1 = NULL; 109 } 110 111 if (productObjA1 != NULL) 112 { 113 delete productObjA1; 114 productObjA1= NULL; 115 } 116 117 if (productObjB1 != NULL) 118 { 119 delete productObjB1; 120 productObjB1 = NULL; 121 } 122 123 if (factoryObj2 != NULL) 124 { 125 delete factoryObj2; 126 factoryObj2 = NULL; 127 } 128 129 if (productObjA2 != NULL) 130 { 131 delete productObjA2; 132 productObjA2 = NULL; 133 } 134 135 if (productObjB2 != NULL) 136 { 137 delete productObjB2; 138 productObjB2 = NULL; 139 } 140 }
參考:
http://blog.csdn.net/wuzhekai1985/article/details/6660462