C++ uses templates to realize abstract engineering mode and prototype mode

C++ uses templates to implement abstract engineering patterns

Abstract factory pattern code part

The more you learn C++, the more you feel that it is an artifact. It is less than 50 lines of code, which not only overcomes the shortcomings of the simple traditional abstract factory model, but is also more convenient to use.
However, compared with the traditional abstract factory model, the abstract factory implemented with templates this time is more abstract and less understandable.
Let us first remove some details, such as permission control, pointer management, etc., and only focus on the idea of ​​this template abstract factory. If you don't want to read the code, you can skip to the second part.

Simplified source code:

//Factory.h
#pragma once
#include<string>
#include<map>
template<class AbstractProduct>
class AbstractRegister {
    
    
public:
	AbstractRegister() = default;
	virtual AbstractProduct* createProduct() = 0;
};
template<class AbstractProduct>
class Factory {
    
    
public:
	static AbstractProduct* createProduct(std::string name) {
    
    
		AbstractRegister<AbstractProduct>* factoryRegister = Factory<AbstractProduct>::name2Product[name];
		return factoryRegister->createProduct();
	}
	static void _factoryRegister(std::string name, AbstractRegister<AbstractProduct>* reg) {
    
    
        name2Product[name] = reg;
	}
	static std::map<std::string, AbstractRegister<AbstractProduct>*> name2Product;
};

template<class AbstractProduct>	//类内静态成员定义外部初始化
std::map<std::string, AbstractRegister<AbstractProduct>*>Factory<AbstractProduct>::name2Product;

template<class AbstractProduct,class Product>	//奇异递归模板
class FactoryRegister : virtual AbstractRegister<AbstractProduct> {
    
    
public:
	static void factoryRegister(std::string name) {
    
    
		Factory<AbstractProduct>::_factoryRegister(name,(AbstractRegister<AbstractProduct>*) new FactoryRegister<AbstractProduct, Product>());
	}
	virtual AbstractProduct* createProduct() {
    
    
		return (AbstractProduct*)new Product();
	}
};

use:

// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include"Factory.h"
#include<string>
using namespace std;
class Food {
    
    
public:
	Food() = default;
	virtual ~Food() = default;
	virtual void show() = 0;
};
class Cake : virtual Food {
    
    
public:
	Cake() {
    
    
		cout << "Food create" << endl;
	}
	virtual ~Cake() {
    
    
		cout << "Food delete" << endl;
	}
	virtual void show() override {
    
    
		cout << "Cake" << endl;
	}
};
int main() {
    
    
	FactoryRegister<Food, Cake>::factoryRegister("cake");	//注册Food工厂,并在其中加入Cake类
	auto cake = Factory<Food>::createProduct("cake");
	cake->show();
}

Template Abstract Factory Ideas

If you are a little confused after reading the source code above, it is normal, and I didn't understand it the first time. But you can listen to me slowly. First, we need to sort out some relationships.

  1. The FactoryRegister class is a class that registers products with the factory, and it is called bidirectionally with the Factory class.
  2. The Factory class is the factory and the template parameter is the abstract product class.
  3. AbstractRegister and FactoryRegister are an inheritance relationship, which means that the pointer of FactoryRegister can be converted into the pointer of AbstractRegister.
  4. AbstractProduct and Product in the template parameters must have an inheritance relationship, otherwise the program cannot run normally.

First of all, the most important thing is the map object in the Factory class. The declaration of map is map<std::string, AbstractRegister*>, kay is a sting, and value is a pointer to the AbstractRegister class. Think about the relationship 3 above, and the value is the AbstractRegister class The pointer of the FactoryRegister is a subclass of AbstractRegister, so as long as the pointer of the FactoryRegister class is converted, the FactoryRegister class can be stored in the map. Using map we get just one FactoryRegister class.

Then we look at the FactoryRegister class. The FactoryRegister class can be said to store the information of the abstract product and the actual product, but here is a template. The FactoryRegister class has two functions factoryRegister() and createProduct(). The factoryRegister() function is provided for external use. It is the interface for users to register products with the factory. createProduct() is provided exclusively for use by the Factory class.

The createProduct() static function of the FactoryRegister class is also quite ingenious. First, createProduct() is a virtual function. When converting to the AbstractRegister class, you can use the FactoryRegister’s own createProduct() function. First, the return value declaration of the virtual function is the same. So the return value is AbstractProduct*, but what we need should be a Product , it doesn’t matter, this is why it is emphasized that AbstractProduct and Product must be an inheritance relationship, we get AbstractProduct and perform a down conversion to get Product*.

Finally, let's look at the use in the main() function. First, in order to test, I define the Food class and the Cake class. The Food class is an abstract product, and the Cake class is an actual product.
First, we use the FactoryRegister<Food, Cake>::factoryRegister("cake") static method, which will call the _factoryRegister static method in the Factory class. Here is a clever conversion. Remember the relationship 3 above, sub The class pointer is converted into a parent class pointer, and the "cake" and FactoryRegister<Food, Cake> class pointers are registered in the map of the Factory class.

When you want to produce a product from the factory, call Factory::createProduct(name), this function will look up the FactoryRegister class in the map according to the name, use the createProduct() function of the FactoryRegister class to create a specific object, and finally return.

Improved version

It is planned to add function access rights and change naked pointers to smart pointers. unfinished. . . . .

prototype pattern

To be honest, the first time I saw the prototype mode, my first reaction was that the constructor could not be done, but after reading a sentence from Mr. Chen Shuo, I found that the Internet is actually nonsense.

The meaning of Prototype is that you get a Base*, which points to a Derived object, and you want to clone the Derived object, but the specific type of Derived is not written in the code, because there are many derived classes. In this case, you use the constructor Functions are messy, and type-switches have bad smells. In addition, the performance loss of virtual is considered here regardless of the primary and secondary, and the construction of the object needs to allocate memory, which is much more expensive than a virtual function call.

Guess you like

Origin blog.csdn.net/ninesnow_c/article/details/119940427
Recommended