设计模式系列(五)工厂方法模式(Factory Method Pattern)
2015-12-04 16:10
453 查看
设计模式系列(五)工厂方法模式(Factory Method Pattern)
工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个,工厂方法让类把实例化推迟到子类。所谓决定,并不是指模式允许子类本身在运行时做决定,而是指在编写创建者类时,不需要知道实际创建的产品是哪一个,选择了使用哪个子类,就自然决定了实际创建的产品是什么。这是一种常用的对象创建型设计模式,此模式的核心精神是封装类中不变的部分,提取其中个性化善变的部分为独立类,通过依赖注入以达到解耦、复用和方便后期维护拓展的目的。工厂方法模式对简单工厂模式进行了抽象。有一个抽象的Factory类(可以是抽象类和接口),这个类将不再负责具体的产品生产,而是只制定一些规范,具体的生产工作由其子类去完成。在这个模式中,工厂类和产品类往往可以依次对应。即一个抽象工厂对应一个抽象产品,一个具体工厂对应一个具体产品,这个具体的工厂就负责生产对应的产品。
工厂方法模式主要有四个角色:
(1)抽象工厂(Creator)角色:是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。
(2)具体工厂(Concrete Creator)角色:这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建产品对象。在上图中有两个这样的角色:BulbCreator与TubeCreator。
(3)抽象产品(Product)角色:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
(4)具体产品(Concrete Product)角色:这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应。
上一篇文章讲述了简单工厂模式。简单工厂是把全部的事情,在一个地方都处理完了,然而工厂方法却是在创建一个框架,让子类来决定要如何实现。比方说在工厂方法中下面的例子中,orderPizza()方法提供了一般的框架,以便创建比萨,orderPizza()方法依赖工厂方法创建具体类,并制造出实际的比萨。可以通过继承PizzaStore类,决定实际制造出的比萨是什么。简单工厂的做法,可以将对象的创建封装起来,但是简单工厂不具备工厂方法的弹性,因为简单工厂不能变更正在创建的产品。
下面我们来看看上面说到的例子,这个例子由三个文件组成,依次是:FactoryMethodPattern.h、FactoryMethodPattern.cpp、FactoryMethodPatternTest.cpp。
// 工厂方法模式 #ifndef FACTORYMETHOD #define FACTORYMETHOD #include <iostream> #include <iomanip> #include <string> #include <vector> using std::string; using std::vector; using std::cout; using std::endl; // 抽象产品角色:比萨 class Pizza { protected: Pizza(){} // 仅限于子类创建该对象 public: string name; // 名字 string dough; // 面团 string sauce; // 酱油 vector<string> toppings; // 调料 virtual ~Pizza(){} string getName(); void prepare(); void bake(); void cut(); void box(); string toString(); }; // 具体产品角色---芝加哥风味的比萨1 class ChicagoStyleClamPizza : public Pizza { public: ChicagoStyleClamPizza() { name = "Chicago Style Clam Pizza"; dough = "Extra Thick Crust Dough"; sauce = "Plum Tomato Sauce"; toppings.push_back("Shredded Mozzarella Cheese"); toppings.push_back("Frozen Clams from Chesapeake Bay"); } void cut(); }; // 具体产品角色---芝加哥风味的比萨2 class ChicagoStyleCheesePizza : public Pizza { public: ChicagoStyleCheesePizza() { name = "Chicago Style Deep Dish Cheese Pizza"; dough = "Extra Thick Crust Dough"; sauce = "Plum Tomato Sauce"; toppings.push_back("Shredded Mozzarella Cheese"); } void cut(); }; // 具体产品角色---芝加哥风味的比萨3 class ChicagoStylePepperoniPizza : public Pizza { public: ChicagoStylePepperoniPizza() { name = "Chicago Style Pepperoni Pizza"; dough = "Extra Thick Crust Dough"; sauce = "Plum Tomato Sauce"; toppings.push_back("Shredded Mozzarella Cheese"); toppings.push_back("Black Olives"); toppings.push_back("Spinach"); toppings.push_back("Eggplant"); toppings.push_back("Sliced Pepperoni"); } void cut(); }; // 具体产品角色---芝加哥风味的比萨4 class ChicagoStyleVeggiePizza : public Pizza { public: ChicagoStyleVeggiePizza() { name = "Chicago Deep Dish Veggie Pizza"; dough = "Extra Thick Crust Dough"; sauce = "Plum Tomato Sauce"; toppings.push_back("Shredded Mozzarella Cheese"); toppings.push_back("Black Olives"); toppings.push_back("Spinach"); toppings.push_back("Eggplant"); } void cut(); }; // 具体产品角色---纽约风味的比萨1 class NYStyleCheesePizza : public Pizza { public: NYStyleCheesePizza() { name = "NY Style Sauce and Cheese Pizza"; dough = "Thin Crust Dough"; sauce = "Marinara Sauce"; toppings.push_back("Grated Reggiano Cheese"); } }; // 具体产品角色---纽约风味的比萨2 class NYStylePepperoniPizza : public Pizza { public: NYStylePepperoniPizza() { name = "NY Style Pepperoni Pizza"; dough = "Thin Crust Dough"; sauce = "Marinara Sauce"; toppings.push_back("Grated Reggiano Cheese"); toppings.push_back("Sliced Pepperoni"); toppings.push_back("Garlic"); toppings.push_back("Onion"); toppings.push_back("Mushrooms"); toppings.push_back("Red Pepper"); } }; // 具体产品角色---纽约风味的比萨3 class NYStyleVeggiePizza : public Pizza { public: NYStyleVeggiePizza() { name = "NY Style Veggie Pizza"; dough = "Thin Crust Dough"; sauce = "Marinara Sauce"; toppings.push_back("Grated Reggiano Cheese"); toppings.push_back("Garlic"); toppings.push_back("Onion"); toppings.push_back("Mushrooms"); toppings.push_back("Red Pepper"); } }; // 具体产品角色---纽约风味的比萨4 class NYStyleClamPizza : public Pizza { public: NYStyleClamPizza() { name = "NY Style Clam Pizza"; dough = "Thin Crust Dough"; sauce = "Marinara Sauce"; toppings.push_back("Grated Reggiano Cheese"); toppings.push_back("Fresh Clams from Long Island Sound"); } }; // 抽象工厂角色:工厂抽象类 class PizzaStore { public: PizzaStore(){} virtual ~PizzaStore(){} // 这个函数接口是工厂方法,由子类实现,将创建对象推迟到子类 virtual Pizza* createPizza(string item) = 0; Pizza* orderPizza(string type) { Pizza* pizza = createPizza(type); cout << "--- Making a " << pizza->getName() << " ---" << endl; pizza->prepare(); pizza->bake(); pizza->cut(); pizza->box(); return pizza; } }; // 具体工厂角色1:芝加哥的工厂 class ChicagoPizzaStore : public PizzaStore { public: Pizza* createPizza(string item); }; // 具体工厂角色2:纽约的工厂 class NYPizzaStore : public PizzaStore { public: Pizza* createPizza(string item); }; #endif
#include "FactoryMethodPattern.h" // 抽象产品角色:比萨 string Pizza::getName() { return name; } void Pizza::prepare() { cout << "Preparing " << name << endl; cout << "Tossing dough..." << endl; cout << "Adding sauce..." << endl; cout << "Adding toppings: " << endl; for (size_t i = 0; i < toppings.size(); i++) { cout << " " + toppings.at(i) << endl; } } void Pizza::bake() { cout << "Bake for 25 minutes at 350" << endl; } void Pizza::cut() { cout << "Cutting the pizza into diagonal slices" << endl; } void Pizza::box() { cout << "Place pizza in official PizzaStore box" << endl; } string Pizza::toString() { // code to display pizza name and ingredients string display; display.append("---- " + name + " ----\n"); display.append(dough + "\n"); display.append(sauce + "\n"); for (size_t i = 0; i < toppings.size(); i++) { display.append(toppings.at(i) + "\n"); } return display; } // 具体产品角色---芝加哥风味的比萨1 void ChicagoStyleClamPizza::cut() { cout << "Cutting the pizza into square slices" << endl; } // 具体产品角色---芝加哥风味的比萨2 void ChicagoStyleCheesePizza::cut() { cout << "Cutting the pizza into square slices" << endl; } // 具体产品角色---芝加哥风味的比萨3 void ChicagoStylePepperoniPizza::cut() { cout << "Cutting the pizza into square slices" << endl; } // 具体产品角色---芝加哥风味的比萨4 void ChicagoStyleVeggiePizza::cut() { cout << "Cutting the pizza into square slices" << endl; } // 具体工厂角色1:芝加哥的工厂 Pizza* ChicagoPizzaStore::createPizza(string item) { if (!item.compare("cheese")) { return new ChicagoStyleCheesePizza(); } else if (!item.compare("veggie")) { return new ChicagoStyleVeggiePizza(); } else if (!item.compare("clam")) { return new ChicagoStyleClamPizza(); } else if (!item.compare("pepperoni")) { return new ChicagoStylePepperoniPizza(); } else { return NULL; } } // 具体工厂角色2:纽约的工厂 Pizza* NYPizzaStore::createPizza(string item) { if (!item.compare("cheese")) { return new NYStyleCheesePizza(); } else if (!item.compare("veggie")) { return new NYStyleVeggiePizza(); } else if (!item.compare("clam")) { return new NYStyleClamPizza(); } else if (!item.compare("pepperoni")) { return new NYStylePepperoniPizza(); } else { return NULL; } }
#include "FactoryMethodPattern.h" void main() { PizzaStore* nyStore = new NYPizzaStore(); PizzaStore* chicagoStore = new ChicagoPizzaStore(); cout << "------------------------------------------------" << endl; Pizza* pizza = nyStore->orderPizza("cheese"); cout << "Ethan ordered a " << pizza->getName() << endl; delete pizza; cout << "------------------------------------------------" << endl; pizza = chicagoStore->orderPizza("cheese"); cout << "Joel ordered a " << pizza->getName() << endl; delete pizza; cout << "------------------------------------------------" << endl; pizza = nyStore->orderPizza("clam"); cout << "Ethan ordered a " << pizza->getName() << endl; delete pizza; cout << "------------------------------------------------" << endl; pizza = chicagoStore->orderPizza("clam"); cout << "Joel ordered a " << pizza->getName() << endl; delete pizza; cout << "------------------------------------------------" << endl; pizza = nyStore->orderPizza("pepperoni"); cout << "Ethan ordered a " << pizza->getName() << endl; delete pizza; cout << "------------------------------------------------" << endl; pizza = chicagoStore->orderPizza("pepperoni"); cout << "Joel ordered a " << pizza->getName() << endl; delete pizza; cout << "------------------------------------------------" << endl; pizza = nyStore->orderPizza("veggie"); cout << "Ethan ordered a " << pizza->getName() << endl; delete pizza; cout << "------------------------------------------------" << endl; pizza = chicagoStore->orderPizza("veggie"); cout << "Joel ordered a " << pizza->getName() << endl; delete pizza; pizza = NULL; cout << "------------------------------------------------" << endl; }
该例的运行结果如图1所示,由于输出较多,所以只有前面的输出部分,后面的大家可以自行运行查看。
图1 部分执行结果
该例的UML类图如图2所示。
图2 UML类图
从图2中可以看出,在工厂方法中必备的角色分别对应于:
(1)抽象产品角色是:Pizza类;
(2)具体产品角色是:后缀为Pizza的8个类(图2中指向Pizza类);
(3)抽象工厂角色是:PizzaStore类,它是抽象类,其中有一个抽象函数即createPizza()函数,这个函数留给子类实现,从而实现了所谓的将实际创建对象的确定留给子类决定;
(4)具体工厂角色是:ChicagoPizzaStore类和NYPizzaStore类,这两个类都各自实现了自己的createPizza()函数,从而实现了不同工厂方法。
上面的例子是一个比萨店的订购系统,和上一篇讲的简单工厂模式是同样的思路,不过实现方法不一样,这里加入了新的比萨店,更为复杂一些,所以可以看出,简单工厂模式主要用于较为简单的对象创建中,当对象较多时,可以采用工厂方法模式,当然,下一篇马上就会讲到抽象工厂模式,在此之前大家先弄懂工厂方法模式。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- PropertyChangeListener简单理解
- 关于指针的一些事情
- 什么是设计模式
- 设计模式之创建型模式 - 特别的变量问题
- 七、设计模式——装饰模式
- 设计模式总结
- 设计模式之创建型模式
- 浅谈设计模式的学习
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题