设计模式系列(五)工厂方法模式(Factory Method Pattern)

设计模式系列(五)工厂方法模式(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所示,由于输出较多,所以只有前面的输出部分,后面的大家可以自行运行查看。

设计模式系列(五)工厂方法模式(Factory Method Pattern)_第1张图片
图1 部分执行结果

    该例的UML类图如图2所示。

设计模式系列(五)工厂方法模式(Factory Method Pattern)_第2张图片
图2 UML类图

    从图2中可以看出,在工厂方法中必备的角色分别对应于:

(1)抽象产品角色是:Pizza类;
(2)具体产品角色是:后缀为Pizza的8个类(图2中指向Pizza类);
(3)抽象工厂角色是:PizzaStore类,它是抽象类,其中有一个抽象函数即createPizza()函数,这个函数留给子类实现,从而实现了所谓的将实际创建对象的确定留给子类决定;
(4)具体工厂角色是:ChicagoPizzaStore类和 NYPizzaStore类,这两个类都各自实现了自己的createPizza()函数,从而实现了不同工厂方法。

    上面的例子是一个比萨店的订购系统,和上一篇讲的简单工厂模式是同样的思路,不过实现方法不一样,这里加入了新的比萨店,更为复杂一些,所以可以看出,简单工厂模式主要用于较为简单的对象创建中,当对象较多时,可以采用工厂方法模式,当然,下一篇马上就会讲到抽象工厂模式,在此之前大家先弄懂工厂方法模式。

你可能感兴趣的:(设计模式,C++,method,factory,工厂方法模式,UML类图,Patte)