introduce
Previous Initial Chapter C++ Deeply and Simply Explain Factory Model (Initial Chapter) The structure, characteristics and defects of simple factory mode, factory method mode and abstract factory mode are described. The above three ways, when adding new products, either modify the factory class, or need to add specific factory class, indicating that the packaging of factory class is not good enough.
The advanced part of this paper mainly improves the encapsulation of the factory class. When new products are added, there is no need to modify the factory class, and no need to add specific factory class. The factory class with high encapsulation is characterized by high scalability and reusability.
Template factory
The factory method pattern is encapsulated into template factory class, so when adding new products, it does not need to add specific factory class, which reduces the amount of coding.
UML diagram:
Template Factory Code:
- Shoes and lothe are abstract classes of shoes and clothes (base classes)
- NiKeShoes and UniqloClothe are specific products of Nike shoes and clothes warehouse respectively.
// Base shoes class Shoes { public: virtual void Show() = 0; virtual ~Shoes() {} }; // Nike shoes class NiKeShoes : public Shoes { public: void Show() { std::cout << "I'm Nike sneakers. My slogan is: Just do it" << std::endl; } }; // Basic clothes class Clothe { public: virtual void Show() = 0; virtual ~Clothe() {} }; // Uniqlo clothes class UniqloClothe : public Clothe { public: void Show() { std::cout << "I'm Uniqlo. My slogan is: I am Uniqlo" << std::endl; } };
- AbstractFactory is an abstract template factory class with template parameters: AbstractProduct_t product Abstract classes, such as Shoes, Clothe
- ConcreteFactory is a concrete template factory class with template parameters: AbstractProduct_t product abstract class (such as Shoes, Clothe) and ConcreteProduct_t product concrete class (such as NiKeShoes, UniqloClothe)
// Abstract template factory class // Template parameter: AbstractProduct_t product abstract class template <class AbstractProduct_t> class AbstractFactory { public: virtual AbstractProduct_t *CreateProduct() = 0; virtual ~AbstractFactory() {} }; // Specific template factory class // Template parameters: AbstractProduct_t product Abstract class, ConcreteProduct_t product concrete class template <class AbstractProduct_t, class ConcreteProduct_t> class ConcreteFactory : public AbstractFactory<AbstractProduct_t> { public: AbstractProduct_t *CreateProduct() { return new ConcreteProduct_t(); } };
- main function, according to different types of products, constructs the factory objects of corresponding products, and then creates specific product objects through the factory objects of corresponding products.
int main() { // Factory Objects for Constructing Nike Shoes ConcreteFactory<Shoes, NiKeShoes> nikeFactory; // Create Nike Shoe Object Shoes *pNiKeShoes = nikeFactory.CreateProduct(); // Print Nike Shoes Advertising Language pNiKeShoes->Show(); // Factory Objects for Constructing Uniqlo Clothes ConcreteFactory<Clothe, UniqloClothe> uniqloFactory; // Create Uniqlo Clothes Object Clothe *pUniqloClothe = uniqloFactory.CreateProduct(); // Print Uniqlo slogans pUniqloClothe->Show(); // Release resources delete pNiKeShoes; pNiKeShoes = NULL; delete pUniqloClothe; pUniqloClothe = NULL; return 0; }
- Output results:
[root@lincoding factory]# ./templateFactory I'm Nike sneakers. My slogan: Just do it I'm Uniqlo. My slogan: I am Uniqlo
Product Registration Template Class + Singleton Factory Template Class
Although the former template factory does not need to add specific factory classes when adding new products, it lacks a class that can unify access to specified product objects at any time and anywhere.
There is room for improvement. We can save the object registered by the product in std::map mode, and get the corresponding product object instance easily and simply by key-valve mode.
To achieve the general idea:
- The function of product registration is encapsulated into product registration template class. Registered product objects are stored in std::map of the factory template class for easy access to product objects.
- The function of obtaining product object is encapsulated into factory template class. In order to obtain the specified product objects anytime and anywhere, the factory is designed as a singleton mode.
UML diagram:
Product Registration Template Class + Singleton Factory Template Class:
- IProductRegistrar registers abstract classes for products, and the class represented by the template parameter ProductType_t is product abstract classes (such as Shoes, Clothe). The pure virtual function CreateProduct for product object creation is provided.
- ProductFactory is the factory template class, and the class represented by the template parameter ProductType_t is the product abstract class (such as Shoes, Clothe). Used to save the registered product object to std::map and get the corresponding product object.
- Product Registrar is a template class for product registration. The class represented by template parameter ProductType_t is product abstract class (such as Shoes, Clothe), and the class represented by Product Impl_t is specific product (such as NikeShoes, UniqloClothe). Used to register products to factory classes and create product instance objects.
// Base class, product registration template interface class // The class represented by the template parameter ProductType_t is the product abstract class template <class ProductType_t> class IProductRegistrar { public: // Getting abstract interface of product object virtual ProductType_t *CreateProduct() = 0; protected: // External construction and fiction are prohibited, and other functions of subclasses "inside" can be called IProductRegistrar() {} virtual ~IProductRegistrar() {} private: // Prohibit external copy and assignment operations IProductRegistrar(const IProductRegistrar &); const IProductRegistrar &operator=(const IProductRegistrar &); }; // Factory template class for acquiring and registering product objects // The class represented by the template parameter ProductType_t is the product abstract class template <class ProductType_t> class ProductFactory { public: // Get the factory singleton, the factory instance is unique static ProductFactory<ProductType_t> &Instance() { static ProductFactory<ProductType_t> instance; return instance; } // Product registration void RegisterProduct(IProductRegistrar<ProductType_t> *registrar, std::string name) { m_ProductRegistry[name] = registrar; } // Get the corresponding specific product object according to the name ProductType_t *GetProduct(std::string name) { // Find the registered product from map and return the product object if (m_ProductRegistry.find(name) != m_ProductRegistry.end()) { return m_ProductRegistry[name]->CreateProduct(); } // Unregistered products are not found std::cout << "No product found for " << name << std::endl; return NULL; } private: // Prohibition of external construction and fiction ProductFactory() {} ~ProductFactory() {} // Prohibit external copy and assignment operations ProductFactory(const ProductFactory &); const ProductFactory &operator=(const ProductFactory &); // Keep registered products, key: product name, value: product type std::map<std::string, IProductRegistrar<ProductType_t> *> m_ProductRegistry; }; // Product registration template class for creating specific products and registering products from factories // The class represented by template parameter ProductType_t is product abstract class (base class), and the class represented by ProductImpl_t is concrete product (subclass of product type) template <class ProductType_t, class ProductImpl_t> class ProductRegistrar : public IProductRegistrar<ProductType_t> { public: // Constructor, used to register products to the factory, can only display calls explicit ProductRegistrar(std::string name) { // Register products to factories through factory singletons ProductFactory<ProductType_t>::Instance().RegisterProduct(this, name); } // Create product-specific object pointers ProductType_t *CreateProduct() { return new ProductImpl_t(); } };
- The main function registers various types of products through the Product Registrar, and obtains the specified product objects from the Unified Product Factory singleton factory.
int main() { // ========================== Production process of Nike sneakers===========================// // Registered products are Shoes (base class), NiKe (subclass) to factory, and the product name is nike. ProductRegistrar<Shoes, NiKeShoes> nikeShoes("nike"); // Get the product type Shoes from the factory and the product object named nike Shoes *pNiKeShoes = ProductFactory<Shoes>::Instance().GetProduct("nike"); // Advertising slogans displaying products pNiKeShoes->Show(); // Release resources if (pNiKeShoes) { delete pNiKeShoes; } // ========================== Production of Uniqlo Clothes===========================// // The registered product category is Clothe (base class), and the product is UniqloClothe (subclass) to the factory. The product name is uniqlo. ProductRegistrar<Clothe, UniqloClothe> adidasShoes("uniqlo"); // Get a product object named adidas from the factory with the product type Shoes Clothe *pUniqloClothe = ProductFactory<Clothe>::Instance().GetProduct("uniqlo"); // Advertising slogans displaying products pUniqloClothe->Show(); // Release resources if (pUniqloClothe) { delete pUniqloClothe; } return 0; }
- Output results:
[root@lincoding factory]# ./singleFactory I'm Nike sneakers. My slogan: Just do it I'm Uniqlo. My slogan: I am Uniqlo
summary
Improving the factory method model into template factory can solve the problem that no specific factory class is needed when new products are added, but it lacks a way to obtain product objects anytime and anywhere, which shows that there is room for improvement.
The template factory is improved into product registration template class + singleton factory template class. The product registration template class is used to register different types of products, and the singleton factory template class is used to obtain the specified registered product objects. In this way, the main functions of product registration and acquisition in factory mode can be well abstracted into two classes, and the use of singleton mode enables factory classes to obtain registered product objects at any time and anywhere.
Therefore, the factory mode of product registration template class + single factory template class achieves the open and close rule, and has high scalability and high encapsulation.
PS: If you want to learn more singleton modes, you can refer to them. Summary of C++ Thread Safety Singleton Patterns Reading articles.