Factory pattern C + + implementation of design pattern

Refer to the book Head First design pattern

Reference article: Design pattern: summary and difference of simple factory, factory method and abstract factory_ superbeck's column - CSDN blog_ Simple factory pattern, factory method pattern, abstract factory pattern, simple factory, factory method and abstract factory all belong to the creation pattern in the design pattern. Its main function is to help us extract the instantiation part of the object, optimize the system architecture and enhance the scalability of the system. This paper is a summary of my study of these three models and my understanding of the differences between them.   The factory class of simple factory pattern generally uses static methods to return different object instances through different received parameters. It cannot be extended without modifying the code.    factoryhttps://blog.csdn.net/superbeck/article/details/4446177

         There are three easily confused patterns mentioned in the factory pattern, namely, simple factory pattern, factory method pattern and abstract factory pattern.

The same point: simple factory, factory method and abstract factory all belong to the creation pattern in design pattern. Its main function is to help us extract the instantiation part of the object, optimize the system architecture and enhance the scalability of the system.

The difference between them is that the factory method pattern uses inheritance, that is, when using factory methods to create objects, you need to extend a class and override its factory methods. The abstract factory pattern is a combination of objects. The abstract factory provides an abstract type used to create a product family. The subclass of this type defines the method by which the product is generated. To use this factory, you must first instantiate it and then pass it into some code written for abstract types.

On the difference and use of simple factory, factory method and abstract factory - program ape canlin - blog Park

Simple factory: used to produce any product in the same hierarchical structure. (there is nothing we can do to add new products)

Factory method: used to produce fixed products in the same grade structure. (any product can be added)  
Abstract factory: used to produce all products of different product families. (there is nothing you can do to add new products; support adding product families)  

1, Simple factory (static factory) mode

         Simple factory is not a design pattern, but more like a programming habit. But because it is often used, it is also called design pattern in many places.

          A simple factory obtains the corresponding product instance by instantiating a factory class. We don't need to pay attention to the details of how the product itself is created. We only need to obtain the corresponding instance through the corresponding factory.

         Factory classes in simple factory mode generally use static methods to return different object instances through different received parameters.

  1.1 class diagram of simple factory mode

The class diagram of simple factory mode is as follows, and the picture is linked Factory model - simple factory model - brief book , invasion and deletion

         The Factory class is the core of the simple Factory pattern. It contains a method for creating products, which is responsible for creating specific products, generally static functions. Generally, the receiving parameter is of enumeration type. The enumeration value determines which specific product to create, and returns the pointer of an abstract product IProduct. The client calls some public interfaces of the product through the returned pointer.

        IProduct product base class is the parent class of all objects created by the simple factory pattern. It is responsible for describing the common interface shared by all instances.

        Product specific product category. Factory methods create objects of this type.

1.2 case description

        Pizza shops can produce all kinds of pizza, such as cheese, green and pepperoni. After pizza is produced, it needs to be prepared, baked, sliced and boxed.

1.3 code implementation

          Declaration: the declaration and implementation of a class in the same file is a bad habit, a bad habit, a bad habit, but because I'm lazy, I still write it together. Don't follow suit. Take a warning, take a warning, take a warning.

        First, define the pizza base class pissa (that is, the IProduct class in the class diagram), and the specific pizza classes CheesePizza and pepperoni pizza (corresponding to the Product in the class diagram). The code is as follows.

//Pizza
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;
};

//Specific pizza
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");
	}
};

        Then there is the simple pizza factory class simplepizzafactory (corresponding to the factory in the class diagram), which contains a static method to produce concrete pizza. The code is as follows

//Pizza factory
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;
	}
};

        The next step is to use the factory code. Define the pizza shop class, which contains a pointer to a pizza factory. Use the factory to produce pizza. The code is as follows

//Test code
//Use the pizza factory to produce 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;
};

        Finally, use the PissaStroe object in the main function to order a cheese pizza and a pepperoni pizza. The code is as follows

//Test code
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 operation results

        

2, Factory method model

         The factory method provides a factory class for each product. Create different product instances through different factory instances.

         The factory method pattern defines an interface for creating objects, but the subclass determines which class to instantiate. Factory methods let classes defer instantiation to subclasses.

        Factory methods are used to handle the creation of objects and encapsulate such behavior in subclasses. In this way, the customer's code about the superclass is decoupled from the subclass object creation code.

2.1 plant method pattern class diagram

The class diagram of factory method pattern is as follows, and the picture is linked Carson teaches you design patterns: Factory Method_ Carson takes you to Android CSDN blog_ Plant method class diagram , invasion and deletion

         The difference from the simple factory pattern is that the simple factory handles the creation of objects in the methods of the factory class, while the factory method pattern encapsulates the processing of specific objects in subclasses. This optimizes the disadvantage of low cohesion in simple factories.

2.2 case description

        Continuing with the case in 1.2, the pizza shop will open two branches, the New York Pizza Shop and the Chicago pizza shop. Each branch needs different pizza tastes due to regional differences, so it needs to use local factories to produce pizza.

2.3 code implementation

         First, define the pizza base class pissa (that is, the Product class in the class diagram), which is the same as that in a simple factory, and then the specific pizza classes NYStyleCheesePizza, NYStylePepperoniPizza, ChicagoStyleCheesePizza, and ChicagoStylePepperoniPizza (corresponding to ProductA or ProductB in the class diagram). The code is as follows.

//Pizza
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;
};

//New York cheese pizza
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");
	}
};

//New York Style Pepperoni pizza
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");
	}
};

//Chicago cheese pizza
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");
	}
};

//Chicago style Pepperoni pizza
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");
	}
};

        Then there are pizza shops and pizza branches in various regions, that is, the pizza store class (corresponding to the Factory in the class diagram), which contains a pure virtual function CreatePizza, that is, the Factory method. NYPizzaStore and ChicagoPizzaStore (corresponding to FactoryA and FactoryB in the class diagram, i.e. specific factories responsible for producing specific pizza) inherit from PizzaStore and implement the Factory method CreatePizza



. The code is as follows

//pizzeria 
class PizzaStore
{
public:

	Pizza* OrderPizza(string pizzaType)
	{
		Pizza* pizza = CreatePizza(pizzaType);
		pizza->prepare();
		pizza->bake();
		pizza->cut();
		pizza->box();
		return pizza;
	}

	//Compared with a simple factory, the responsibility for instantiating pizza is transferred to a method, which is like a factory.
	virtual Pizza* CreatePizza(string pizzaType) = 0;
};

//New York Pizza branch
class NYPizzaStore :public PizzaStore
{
public:
	virtual Pizza* CreatePizza(string pizzaType)
	{
		if (pizzaType == "cheese")
			return new NYStyleCheesePizza();
		else if (pizzaType == "pepperoni")
			return  new NYStylePepperoniPizza();
		else
			return nullptr;
	}
};

//Chicago pizza branch
class ChicagoPizzaStore :public PizzaStore
{
public:
	virtual Pizza* CreatePizza(string pizzaType)
	{
		if (pizzaType == "cheese")
			return new ChicagoStyleCheesePizza();
		else if (pizzaType == "pepperoni")
			return new ChicagoStylePepperoniPizza();
		else
			return nullptr;
	}
};

        Finally, the test code. First instantiate two different pizza shops, and then order cheese pizza with different flavors in different shops. The code is as follows

        

//Test code
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 operation results

3, Abstract factory pattern

         Abstract factory is to deal with the concept of product family. For example, every automobile company may produce cars, trucks and buses at the same time, so every factory must have a method to create cars, trucks and buses.

       The abstract factory pattern provides an interface for creating families of related or dependent objects without explicitly specifying specific classes.

The task of the abstract factory is to define an interface responsible for creating a set of products. Each method in this interface is responsible for creating a specific product, and we use subclasses that implement the abstract factory to provide these specific practices. Therefore, it is quite natural to use factory method to realize production method in abstract factory.

3.1 abstract factory pattern class diagram

         The class diagram of abstract factory pattern is as follows, and the picture is linked Design pattern: summary and difference of simple factory, factory method and abstract factory_ superbeck's column - CSDN blog_ Simple factory pattern, factory method pattern, abstract factory pattern , invasion and deletion

3.2 case description

        Continuing with the case in 2.2, the pizza shop wants to expand its business. In addition to producing pizza, it also begins to produce cakes (such a shop looks neither fish nor fowl, because I made it up, ha ha ha). Pizza factories in each different region can produce local pizza and cake (pizza and cake are two different product families).

3.3 code implementation

#include <string>
#include <vector>
#include <iostream>

using namespace std;

//Pizza
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;
};

//New York cheese pizza
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");
	}
};

//New York Style Pepperoni pizza
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");
	}
};

//Chicago cheese pizza
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");
	}
};

//Chicago style Pepperoni pizza
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;
};

//New York Style cookies
class NYStyleSweetCake :public Cake
{
public:
	NYStyleSweetCake()
	{
		m_name = "NY Style Sweet Cake";
	}
};

//New York salty cake
class NYStyleSaltyCake :public Cake
{
public:
	NYStyleSaltyCake()
	{
		m_name = "NY Style salty cake";
	}
};

//Chicago style cookies
class ChicagoStyleSweetCake :public Cake
{
public:
	ChicagoStyleSweetCake()
	{
		m_name = "Chicago Style Sweet Cake";
	}
};

//Chicago salted cake
class ChicagoStyleSaltyCake :public Cake
{
public:
	ChicagoStyleSaltyCake()
	{
		m_name = "Chicago Style salty cake";
	}
};

//Test code
//pizzeria 
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;
	}

	//Compared with a simple factory, the responsibility for instantiating pizza is transferred to a method, which is like a factory.
	virtual Pizza* CreatePizza(string pizzaType) = 0;
	virtual Cake* CreateCake(string cakeType) = 0;
};

//New York Pizza branch
class NYPizzaStore :public PizzaStore
{
public:
	virtual Pizza* CreatePizza(string pizzaType)
	{
		if (pizzaType == "cheese")
			return new NYStyleCheesePizza();
		else if (pizzaType == "pepperoni")
			return  new NYStylePepperoniPizza();
		else
			return nullptr;
	}

	virtual Cake* CreateCake(string cakeType)
	{
		if (cakeType == "sweet")
			return new NYStyleSweetCake();
		else if (cakeType == "salty")
			return new NYStyleSaltyCake();
		else
			return nullptr;
	}
};

//Chicago pizza branch
class ChicagoPizzaStore :public PizzaStore
{
public:
	virtual Pizza* CreatePizza(string pizzaType)
	{
		if (pizzaType == "cheese")
			return new ChicagoStyleCheesePizza();
		else if (pizzaType == "pepperoni")
			return new ChicagoStylePepperoniPizza();
		else
			return nullptr;
	}

	virtual Cake* CreateCake(string cakeType)
	{
		if (cakeType == "sweet")
			return new ChicagoStyleSweetCake();
		else if (cakeType == "salty")
			return new ChicagoStyleSaltyCake();
		else
			return nullptr;
	}
};

//Test code
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");
}

Output results

ps: if the three modes are written together, it will be careless and smelly and long.

 

Keywords: Java html

Added by sawade on Sat, 06 Nov 2021 02:04:14 +0200