工厂模式C++实现
參考書籍《Head First設計模式》
參考文章:設計模式:簡單工廠、工廠方法、抽象工廠之小結與區(qū)別_superbeck的專欄-CSDN博客_簡單工廠模式,工廠方法模式,抽象工廠模式簡單工廠,工廠方法,抽象工廠都屬于設計模式中的創(chuàng)建型模式。其主要功能都是幫助我們把對象的實例化部分抽取了出來,優(yōu)化了系統(tǒng)的架構,并且增強了系統(tǒng)的擴展性。本文是本人對這三種模式學習后的一個小結以及對他們之間的區(qū)別的理解。?簡單工廠簡單工廠模式的工廠類一般是使用靜態(tài)方法,通過接收的參數(shù)的不同來返回不同的對象實例。不修改代碼的話,是無法擴展的。??工廠https://blog.csdn.net/superbeck/article/details/4446177
????????提到工廠模式有三種比較容易混淆的模式,分別是簡單工廠模式、工廠方法模式和抽象工廠模式。
相同點:簡單工廠,工廠方法,抽象工廠都屬于設計模式中的創(chuàng)建型模式。其主要功能都是幫助我們把對象的實例化部分抽取了出來,優(yōu)化了系統(tǒng)的架構,并且增強了系統(tǒng)的擴展性。
它們之間的區(qū)別是:工廠方法模式用的是繼承,即利用工廠方法創(chuàng)建對象時,需要擴展一個類,并覆蓋它的工廠方法。抽象工廠模式是通過對象的組合,抽象工廠提供一個用來創(chuàng)建一個產品家族的抽象類型,這個類型的子類定義了產品被產生的方法。要想使用這個工廠,必須先實例化它,然后將它傳入一些針對抽象類型所寫的代碼中。
淺談簡單工廠,工廠方法,抽象工廠的區(qū)別和使用 - 程序猿燦林 - 博客園
簡單工廠 : 用來生產同一等級結構中的任意產品。(對于增加新的產品,無能為力)
工廠方法 :用來生產同一等級結構中的固定產品。(支持增加任意產品) ?
抽象工廠 :用來生產不同產品族的全部產品。(對于增加新的產品,無能為力;支持增加產品族) ?
一、簡單工廠(靜態(tài)工廠)模式
????????簡單工廠其實不是一個設計模式,反而比較像是一種編程習慣。但由于經常被使用,很多地方也都把它叫做設計模式。
?????????簡單工廠通過實例化一個工廠類,來獲取對應的產品實例。我們不需要關注產品本身如何被創(chuàng)建的細節(jié),只需要通過相應的工廠就可以獲得相應的實例。
????????簡單工廠模式的工廠類一般是使用靜態(tài)方法,通過接收的參數(shù)的不同來返回不同的對象實例。
?1.1 簡單工廠模式的類圖
簡單工廠模式的類圖如下,圖片鏈接工廠模式--簡單工廠模式 - 簡書,侵刪
???????? Factory工廠類,簡單工廠模式的核心。其包含一個創(chuàng)建產品的方法,負責創(chuàng)建具體的產品,一般為靜態(tài)函數(shù)。一般接收參數(shù)為枚舉類型,通過枚舉值確定創(chuàng)建哪一個具體產品,返回一個抽象產品IProduct的指針。客戶端通過返回的指針調用產品的一些公共接口。
??????? IProduct產品基類,簡單工廠模式所創(chuàng)建的所有對象的父類,它負責描述所有實例所共有的公共接口。
??????? Product具體產品類。工廠方法種創(chuàng)建出的就是該類型的對象。
1.2 案列描述
??????? 披薩店可以生產各種口味的披薩,比如cheese口味,greek口味和pepperoni口味。披薩生產出來后需要準備、烘烤、切片、裝盒的工作。
1.3 代碼實現(xiàn)
?????????聲明:類的聲明和實現(xiàn)在同一個文件里是個壞習慣,壞習慣,壞習慣,但因為我懶,還是寫一起了,大家不要效仿,要引以為戒,要引以為戒,要引以為戒。
??????? 首先定義披薩類基類Pissa(就是類圖中的IProduct類),和具體披薩類CheesePizza和PepperoniPizza(對應于類圖中的Product),代碼如下。
//披薩類 class Pizza{ public:void prepare(){cout << "Preparing " << m_name << "..." << endl;cout << "Tossing " << m_name << "..." << endl;cout << "Add " << m_sauce<< "..." << endl;cout << "Add toppings: ";for (vector<string>::iterator it = m_toppings.begin(); it != m_toppings.end(); it++){cout << " " << *it;}cout << endl;}void bake(){cout << "Bake for 25 minutes at 350 "<< endl;;}void cut(){cout << "Cutting the pizza into diagonal slices" << endl;;}void box(){cout << "Place pizza in official pizzaStore box " << endl;;}string getName(){return m_name;} protected:string m_name;string m_dough;string m_sauce;vector<string>m_toppings; };//具體披薩 class CheesePizza :public Pizza { public:CheesePizza(){m_name = "Cheese Pizza"; m_dough = "Thin crust dough";m_sauce = "Marinara Sauce";m_toppings.push_back("Grated Reggiano Cheese");} };class PepperoniPizza :public Pizza { public:PepperoniPizza(){m_name = "Pepperoni Pizza";m_dough = "Thick crust dough";m_sauce = "Plum tomato sauce";m_toppings.push_back("Pepperoni");} };??????? 然后是簡單披薩工廠類SimplePizzaFactory(對應于類圖中的Factory),其包含一個靜態(tài)方法來生產具體披薩。代碼如下
//披薩工廠 class SimplePizzaFactory{ public:static Pizza* CreatePizza(string pizzaType){Pizza* pizza = nullptr;if (pizzaType == "cheese")pizza = new CheesePizza();else if (pizzaType == "pepperoni")pizza = new PepperoniPizza();return pizza;} };??????? 接下來就是使用工廠的代碼了。定義披薩店類,其包含一個披薩工廠的指針,使用該工廠生產披薩,代碼如下
//測試代碼 //使用披薩工廠生產披薩 class PizzaStore { public:PizzaStore(SimplePizzaFactory* factory){m_factory = factory;}Pizza* OrderPizza(string pizzaType){Pizza* pizza = m_factory->CreatePizza(pizzaType);pizza->prepare();pizza->bake();pizza->cut();pizza->box();return pizza;} private:SimplePizzaFactory* m_factory; };??????? 最后,在main函數(shù)中使用PissaStroe對象定一個cheese披薩和一個pepperoni披薩。代碼如下
//測試代碼 int main() {SimplePizzaFactory factory;PizzaStore pizzaStore(&factory);Pizza* pizza = pizzaStore.OrderPizza("cheese");cout << "Order a " << pizza->getName()<<endl<<endl;pizza = pizzaStore.OrderPizza("pepperoni");cout << "Order a " << pizza->getName() << endl;system("pause"); }?? 1.4 運行結果
????????
二、工廠方法模式
????????工廠方法是針對每一種產品提供一個工廠類。通過不同的工廠實例來創(chuàng)建不同的產品實例。
????????工廠方法模式定義了一個創(chuàng)建對象的接口,但由子類決定要實例化的類是哪一個。工廠方法讓類把實例化推遲到子類。
??????? 工廠方法用來處理對象的創(chuàng)建,并將這樣的行為封裝在子類中。這樣客戶關于超類的代碼就和子類對象創(chuàng)建代碼解耦了。
2.1 工廠方法模式類圖
工廠方法模式類圖如下, 圖片鏈接Carson帶你學設計模式:工廠方法模式(Factory Method)_Carson帶你學Android-CSDN博客_工廠方法類圖,侵刪
???????? 與簡單工廠模式的不同之處是,簡單工廠是在工廠類的方法中處理對象的創(chuàng)建,而工廠方法模式是將針對具體對象的處理封裝在子類中。這樣就優(yōu)化了簡單工廠中內聚性低的缺點。
2.2 案列描述
??????? 繼續(xù)1.2中的案例,披薩店要開兩個分店,紐約披薩店和芝加哥披薩店。每個分店因為區(qū)域差異,需要的披薩口味不同,就需要用當?shù)氐墓S生產披薩。
2.3 代碼實現(xiàn)
????????首先定義披薩類基類Pissa(就是類圖中的Product類)這個與簡單工廠中一樣,然后是具體披薩類NYStyleCheesePizza、NYStylePepperoniPizza、ChicagoStyleCheesePizza、和ChicagoStylePepperoniPizza(對應于類圖中的ProductA或ProductB),代碼如下。
//披薩類 class Pizza{ public:void prepare(){cout << "Preparing " << m_name << "..." << endl;cout << "Tossing " << m_name << "..." << endl;cout << "Add " << m_sauce << "..." << endl;cout << "Add toppings: ";for (vector<string>::iterator it = m_toppings.begin(); it != m_toppings.end(); it++){cout << " " << *it;}cout << endl;}void bake(){cout << "Bake for 25 minutes at 350 " << endl;;}void cut(){cout << "Cutting the pizza into diagonal slices" << endl;;}void box(){cout << "Place pizza in official pizzaStore box " << endl;;}string getName(){return m_name;} protected:string m_name;string m_dough;string m_sauce;vector<string>m_toppings; };//紐約風味奶酪披薩 class NYStyleCheesePizza :public Pizza { public:NYStyleCheesePizza(){m_name = "NY Style Cheese Pizza";m_dough = "Thin crust dough";m_sauce = "Marinara Sauce";m_toppings.push_back("Grated Reggiano Cheese");} };//紐約風味Pepperoni披薩 class NYStylePepperoniPizza :public Pizza { public:NYStylePepperoniPizza(){m_name = "NY Style Pepperoni Pizza";m_dough = "Thick crust dough";m_sauce = "Plum tomato sauce";m_toppings.push_back("A lot Pepperoni");} };//芝加哥風味奶酪披薩 class ChicagoStyleCheesePizza :public Pizza { public:ChicagoStyleCheesePizza(){m_name = "Chicago Style Cheese Pizza";m_dough = "Extra Thik crust dough";m_sauce = "Plum Tomato Sauce";m_toppings.push_back("Shredded Mozzarella Cheese");} };//芝加哥風味Pepperoni披薩 class ChicagoStylePepperoniPizza :public Pizza { public:ChicagoStylePepperoniPizza(){m_name = "Chicago Style Pepperoni Pizza";m_dough = "Thick crust dough";m_sauce = "Plum tomato sauce";m_toppings.push_back("A little Pepperoni");} };??????? 然后是披薩店和各個區(qū)域的披薩分店即PizzaStore類(對應與類圖中的Factory),該類中聲包含一個純虛函數(shù)CreatePizza,即工廠方法。 NYPizzaStore和ChicagoPizzaStore(對應與類圖中的FactoryA和FactoryB即具體工廠,負責生產具體的披薩)繼承自PizzaStore,實現(xiàn)工廠方法CreatePizza
。代碼如下
??????? 最后是測試代碼。首先實例化兩個不同的披薩店,然后用不同的店訂不同風味的奶酪披薩。代碼如下
????????
//測試代碼 int main() {PizzaStore* nyStore = new NYPizzaStore();PizzaStore* chicagoStore = new ChicagoPizzaStore();Pizza* pizza = nyStore->OrderPizza("cheese");cout << "Order a " << pizza->getName() << endl << endl;delete pizza;pizza = chicagoStore->OrderPizza("cheese");cout << "Order a " << pizza->getName() << endl;delete nyStore;delete chicagoStore;delete pizza;system("pause"); }??????? 2.4 運行結果
三、抽象工廠模式
????????抽象工廠是應對產品族概念的。比如說,每個汽車公司可能要同時生產轎車,貨車,客車,那么每一個工廠都要有創(chuàng)建轎車,貨車和客車的方法。
?????? 抽象工廠模式提供一個接口,用于創(chuàng)建相關或依賴對象的家族,而不需要明確指定具體類。
抽象工廠的任務是定義一個負責創(chuàng)建一組產品的接口。這個接口內的每個方法都負責創(chuàng)建一個具體產品,同時我們利用實現(xiàn)抽象工廠的子類來提供這些具體的做法。所以,在抽象工廠中利用工廠方法實現(xiàn)生產方法是相當自然的做法。
3.1 抽象工廠模式類圖
????????抽象工廠模式類圖如下, 圖片鏈接設計模式:簡單工廠、工廠方法、抽象工廠之小結與區(qū)別_superbeck的專欄-CSDN博客_簡單工廠模式,工廠方法模式,抽象工廠模式,侵刪
3.2 案列描述
??????? 繼續(xù)2.2中的案例,披薩店想要擴展自己的業(yè)務,除了生產披薩,也開始生產蛋糕(這樣的店看上去不倫不類,因為是我瞎編的,哈哈哈)。每個不同區(qū)域的披薩工廠可以生產當?shù)仫L味的披薩和蛋糕(披薩和蛋糕是兩個不同的產品族)。
3.3 代碼實現(xiàn)
#include <string> #include <vector> #include <iostream>using namespace std;//披薩類 class Pizza{ public:void prepare(){cout << "Preparing " << m_name << "..." << endl;cout << "Tossing " << m_name << "..." << endl;cout << "Add " << m_sauce << "..." << endl;cout << "Add toppings: ";for (vector<string>::iterator it = m_toppings.begin(); it != m_toppings.end(); it++){cout << " " << *it;}cout << endl;}void bake(){cout << "Bake for 25 minutes at 350 " << endl;;}void cut(){cout << "Cutting the pizza into diagonal slices" << endl;;}void box(){cout << "Place pizza in official pizzaStore box " << endl;;}string getName(){return m_name;} protected:string m_name;string m_dough;string m_sauce;vector<string>m_toppings; };//紐約風味奶酪披薩 class NYStyleCheesePizza :public Pizza { public:NYStyleCheesePizza(){m_name = "NY Style Cheese Pizza";m_dough = "Thin crust dough";m_sauce = "Marinara Sauce";m_toppings.push_back("Grated Reggiano Cheese");} };//紐約風味Pepperoni披薩 class NYStylePepperoniPizza :public Pizza { public:NYStylePepperoniPizza(){m_name = "NY Style Pepperoni Pizza";m_dough = "Thick crust dough";m_sauce = "Plum tomato sauce";m_toppings.push_back("A lot Pepperoni");} };//芝加哥風味奶酪披薩 class ChicagoStyleCheesePizza :public Pizza { public:ChicagoStyleCheesePizza(){m_name = "Chicago Style Cheese Pizza";m_dough = "Extra Thik crust dough";m_sauce = "Plum Tomato Sauce";m_toppings.push_back("Shredded Mozzarella Cheese");} };//芝加哥風味Pepperoni披薩 class ChicagoStylePepperoniPizza :public Pizza { public:ChicagoStylePepperoniPizza(){m_name = "Chicago Style Pepperoni Pizza";m_dough = "Thick crust dough";m_sauce = "Plum tomato sauce";m_toppings.push_back("A little Pepperoni");} };class Cake { public:string getName(){return m_name;}void bake(){cout << "Bake for 15 minutes at 130 " << endl;;}void box(){cout << "Place cake in official cake box " << endl;;} protected:string m_name; };//紐約風味甜餅 class NYStyleSweetCake :public Cake { public:NYStyleSweetCake(){m_name = "NY Style Sweet Cake";} };//紐約風味咸餅 class NYStyleSaltyCake :public Cake { public:NYStyleSaltyCake(){m_name = "NY Style salty cake";} };//芝加哥風味甜餅 class ChicagoStyleSweetCake :public Cake { public:ChicagoStyleSweetCake(){m_name = "Chicago Style Sweet Cake";} };//芝加哥風味咸餅 class ChicagoStyleSaltyCake :public Cake { public:ChicagoStyleSaltyCake(){m_name = "Chicago Style salty cake";} };//測試代碼 //披薩店 class PizzaStore { public:Pizza* OrderPizza(string pizzaType){Pizza* pizza = CreatePizza(pizzaType);pizza->prepare();pizza->bake();pizza->cut();pizza->box();return pizza;}Cake* OrderCake(string cakeType){Cake* cake = CreateCake(cakeType);cake->bake();cake->box();return cake;}//與簡單工廠相比,實例化披薩的責任被移到一個方法,此方法如同是一個工廠。virtual Pizza* CreatePizza(string pizzaType) = 0;virtual Cake* CreateCake(string cakeType) = 0; };//紐約披薩分店 class NYPizzaStore :public PizzaStore { public:virtual Pizza* CreatePizza(string pizzaType){if (pizzaType == "cheese")return new NYStyleCheesePizza();else if (pizzaType == "pepperoni")return new NYStylePepperoniPizza();elsereturn nullptr;}virtual Cake* CreateCake(string cakeType){if (cakeType == "sweet")return new NYStyleSweetCake();else if (cakeType == "salty")return new NYStyleSaltyCake();elsereturn nullptr;} };//芝加哥披薩分店 class ChicagoPizzaStore :public PizzaStore { public:virtual Pizza* CreatePizza(string pizzaType){if (pizzaType == "cheese")return new ChicagoStyleCheesePizza();else if (pizzaType == "pepperoni")return new ChicagoStylePepperoniPizza();elsereturn nullptr;}virtual Cake* CreateCake(string cakeType){if (cakeType == "sweet")return new ChicagoStyleSweetCake();else if (cakeType == "salty")return new ChicagoStyleSaltyCake();elsereturn nullptr;} };//測試代碼 int main() {PizzaStore* nyStore = new NYPizzaStore();PizzaStore* chicagoStore = new ChicagoPizzaStore();Pizza* pizza = nyStore->OrderPizza("cheese");cout << "Order a " << pizza->getName() << endl;Cake* cake = nyStore->OrderCake("sweet");cout << "Order a " << cake->getName() << endl<<endl;delete pizza;delete cake;pizza = chicagoStore->OrderPizza("cheese");cout << "Order a " << pizza->getName() << endl;cake = chicagoStore->OrderCake("sweet");cout << "Order a " << cake->getName() << endl;delete nyStore;delete chicagoStore;delete pizza;system("pause"); }輸出結果
ps:三個模式放在一起寫,就一不小心又臭又長了。
總結
- 上一篇: redis的hscan命令
- 下一篇: 【C++】01