工厂模式C++实现
參考書籍《Head First設(shè)計模式》
參考文章:設(shè)計模式:簡單工廠、工廠方法、抽象工廠之小結(jié)與區(qū)別_superbeck的專欄-CSDN博客_簡單工廠模式,工廠方法模式,抽象工廠模式簡單工廠,工廠方法,抽象工廠都屬于設(shè)計模式中的創(chuàng)建型模式。其主要功能都是幫助我們把對象的實例化部分抽取了出來,優(yōu)化了系統(tǒng)的架構(gòu),并且增強(qiáng)了系統(tǒng)的擴(kuò)展性。本文是本人對這三種模式學(xué)習(xí)后的一個小結(jié)以及對他們之間的區(qū)別的理解。?簡單工廠簡單工廠模式的工廠類一般是使用靜態(tài)方法,通過接收的參數(shù)的不同來返回不同的對象實例。不修改代碼的話,是無法擴(kuò)展的。??工廠https://blog.csdn.net/superbeck/article/details/4446177
????????提到工廠模式有三種比較容易混淆的模式,分別是簡單工廠模式、工廠方法模式和抽象工廠模式。
相同點:簡單工廠,工廠方法,抽象工廠都屬于設(shè)計模式中的創(chuàng)建型模式。其主要功能都是幫助我們把對象的實例化部分抽取了出來,優(yōu)化了系統(tǒng)的架構(gòu),并且增強(qiáng)了系統(tǒng)的擴(kuò)展性。
它們之間的區(qū)別是:工廠方法模式用的是繼承,即利用工廠方法創(chuàng)建對象時,需要擴(kuò)展一個類,并覆蓋它的工廠方法。抽象工廠模式是通過對象的組合,抽象工廠提供一個用來創(chuàng)建一個產(chǎn)品家族的抽象類型,這個類型的子類定義了產(chǎn)品被產(chǎn)生的方法。要想使用這個工廠,必須先實例化它,然后將它傳入一些針對抽象類型所寫的代碼中。
淺談簡單工廠,工廠方法,抽象工廠的區(qū)別和使用 - 程序猿燦林 - 博客園
簡單工廠 : 用來生產(chǎn)同一等級結(jié)構(gòu)中的任意產(chǎn)品。(對于增加新的產(chǎn)品,無能為力)
工廠方法 :用來生產(chǎn)同一等級結(jié)構(gòu)中的固定產(chǎn)品。(支持增加任意產(chǎn)品) ?
抽象工廠 :用來生產(chǎn)不同產(chǎn)品族的全部產(chǎn)品。(對于增加新的產(chǎn)品,無能為力;支持增加產(chǎn)品族) ?
一、簡單工廠(靜態(tài)工廠)模式
????????簡單工廠其實不是一個設(shè)計模式,反而比較像是一種編程習(xí)慣。但由于經(jīng)常被使用,很多地方也都把它叫做設(shè)計模式。
?????????簡單工廠通過實例化一個工廠類,來獲取對應(yīng)的產(chǎn)品實例。我們不需要關(guān)注產(chǎn)品本身如何被創(chuàng)建的細(xì)節(jié),只需要通過相應(yīng)的工廠就可以獲得相應(yīng)的實例。
????????簡單工廠模式的工廠類一般是使用靜態(tài)方法,通過接收的參數(shù)的不同來返回不同的對象實例。
?1.1 簡單工廠模式的類圖
簡單工廠模式的類圖如下,圖片鏈接工廠模式--簡單工廠模式 - 簡書,侵刪
???????? Factory工廠類,簡單工廠模式的核心。其包含一個創(chuàng)建產(chǎn)品的方法,負(fù)責(zé)創(chuàng)建具體的產(chǎn)品,一般為靜態(tài)函數(shù)。一般接收參數(shù)為枚舉類型,通過枚舉值確定創(chuàng)建哪一個具體產(chǎn)品,返回一個抽象產(chǎn)品IProduct的指針。客戶端通過返回的指針調(diào)用產(chǎn)品的一些公共接口。
??????? IProduct產(chǎn)品基類,簡單工廠模式所創(chuàng)建的所有對象的父類,它負(fù)責(zé)描述所有實例所共有的公共接口。
??????? Product具體產(chǎn)品類。工廠方法種創(chuàng)建出的就是該類型的對象。
1.2 案列描述
??????? 披薩店可以生產(chǎn)各種口味的披薩,比如cheese口味,greek口味和pepperoni口味。披薩生產(chǎn)出來后需要準(zhǔn)備、烘烤、切片、裝盒的工作。
1.3 代碼實現(xiàn)
?????????聲明:類的聲明和實現(xiàn)在同一個文件里是個壞習(xí)慣,壞習(xí)慣,壞習(xí)慣,但因為我懶,還是寫一起了,大家不要效仿,要引以為戒,要引以為戒,要引以為戒。
??????? 首先定義披薩類基類Pissa(就是類圖中的IProduct類),和具體披薩類CheesePizza和PepperoniPizza(對應(yīng)于類圖中的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(對應(yīng)于類圖中的Factory),其包含一個靜態(tài)方法來生產(chǎn)具體披薩。代碼如下
//披薩工廠 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;} };??????? 接下來就是使用工廠的代碼了。定義披薩店類,其包含一個披薩工廠的指針,使用該工廠生產(chǎn)披薩,代碼如下
//測試代碼 //使用披薩工廠生產(chǎn)披薩 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 運行結(jié)果
????????
二、工廠方法模式
????????工廠方法是針對每一種產(chǎn)品提供一個工廠類。通過不同的工廠實例來創(chuàng)建不同的產(chǎn)品實例。
????????工廠方法模式定義了一個創(chuàng)建對象的接口,但由子類決定要實例化的類是哪一個。工廠方法讓類把實例化推遲到子類。
??????? 工廠方法用來處理對象的創(chuàng)建,并將這樣的行為封裝在子類中。這樣客戶關(guān)于超類的代碼就和子類對象創(chuàng)建代碼解耦了。
2.1 工廠方法模式類圖
工廠方法模式類圖如下, 圖片鏈接Carson帶你學(xué)設(shè)計模式:工廠方法模式(Factory Method)_Carson帶你學(xué)Android-CSDN博客_工廠方法類圖,侵刪
???????? 與簡單工廠模式的不同之處是,簡單工廠是在工廠類的方法中處理對象的創(chuàng)建,而工廠方法模式是將針對具體對象的處理封裝在子類中。這樣就優(yōu)化了簡單工廠中內(nèi)聚性低的缺點。
2.2 案列描述
??????? 繼續(xù)1.2中的案例,披薩店要開兩個分店,紐約披薩店和芝加哥披薩店。每個分店因為區(qū)域差異,需要的披薩口味不同,就需要用當(dāng)?shù)氐墓S生產(chǎn)披薩。
2.3 代碼實現(xiàn)
????????首先定義披薩類基類Pissa(就是類圖中的Product類)這個與簡單工廠中一樣,然后是具體披薩類NYStyleCheesePizza、NYStylePepperoniPizza、ChicagoStyleCheesePizza、和ChicagoStylePepperoniPizza(對應(yīng)于類圖中的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; };//紐約風(fēng)味奶酪披薩 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");} };//紐約風(fēng)味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");} };//芝加哥風(fēng)味奶酪披薩 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");} };//芝加哥風(fēng)味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類(對應(yīng)與類圖中的Factory),該類中聲包含一個純虛函數(shù)CreatePizza,即工廠方法。 NYPizzaStore和ChicagoPizzaStore(對應(yīng)與類圖中的FactoryA和FactoryB即具體工廠,負(fù)責(zé)生產(chǎn)具體的披薩)繼承自PizzaStore,實現(xiàn)工廠方法CreatePizza
。代碼如下
??????? 最后是測試代碼。首先實例化兩個不同的披薩店,然后用不同的店訂不同風(fēng)味的奶酪披薩。代碼如下
????????
//測試代碼 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 運行結(jié)果
三、抽象工廠模式
????????抽象工廠是應(yīng)對產(chǎn)品族概念的。比如說,每個汽車公司可能要同時生產(chǎn)轎車,貨車,客車,那么每一個工廠都要有創(chuàng)建轎車,貨車和客車的方法。
?????? 抽象工廠模式提供一個接口,用于創(chuàng)建相關(guān)或依賴對象的家族,而不需要明確指定具體類。
抽象工廠的任務(wù)是定義一個負(fù)責(zé)創(chuàng)建一組產(chǎn)品的接口。這個接口內(nèi)的每個方法都負(fù)責(zé)創(chuàng)建一個具體產(chǎn)品,同時我們利用實現(xiàn)抽象工廠的子類來提供這些具體的做法。所以,在抽象工廠中利用工廠方法實現(xiàn)生產(chǎn)方法是相當(dāng)自然的做法。
3.1 抽象工廠模式類圖
????????抽象工廠模式類圖如下, 圖片鏈接設(shè)計模式:簡單工廠、工廠方法、抽象工廠之小結(jié)與區(qū)別_superbeck的專欄-CSDN博客_簡單工廠模式,工廠方法模式,抽象工廠模式,侵刪
3.2 案列描述
??????? 繼續(xù)2.2中的案例,披薩店想要擴(kuò)展自己的業(yè)務(wù),除了生產(chǎn)披薩,也開始生產(chǎn)蛋糕(這樣的店看上去不倫不類,因為是我瞎編的,哈哈哈)。每個不同區(qū)域的披薩工廠可以生產(chǎn)當(dāng)?shù)仫L(fēng)味的披薩和蛋糕(披薩和蛋糕是兩個不同的產(chǎn)品族)。
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; };//紐約風(fēng)味奶酪披薩 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");} };//紐約風(fēng)味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");} };//芝加哥風(fēng)味奶酪披薩 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");} };//芝加哥風(fēng)味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; };//紐約風(fēng)味甜餅 class NYStyleSweetCake :public Cake { public:NYStyleSweetCake(){m_name = "NY Style Sweet Cake";} };//紐約風(fēng)味咸餅 class NYStyleSaltyCake :public Cake { public:NYStyleSaltyCake(){m_name = "NY Style salty cake";} };//芝加哥風(fēng)味甜餅 class ChicagoStyleSweetCake :public Cake { public:ChicagoStyleSweetCake(){m_name = "Chicago Style Sweet Cake";} };//芝加哥風(fēng)味咸餅 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;}//與簡單工廠相比,實例化披薩的責(zé)任被移到一個方法,此方法如同是一個工廠。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"); }輸出結(jié)果
ps:三個模式放在一起寫,就一不小心又臭又長了。
總結(jié)
- 上一篇: redis的hscan命令
- 下一篇: DAO,除了协议、社交、媒体、服务之外还