
Абстрактна фабрика на C++
Абстрактна фабрика — це породжуючий патерн проектування, який вирішує проблему створення цілих сімейств пов’язаних продуктів, без прив’язки коду до конкретних класів продуктів.
Абстрактна фабрика задає інтерфейс створення всіх доступних типів продуктів, а кожна конкретна реалізація фабрики породжує продукти однієї з варіацій. Клієнтський код викликає методи фабрики для отримання продуктів, замість самостійного створювання їх за допомогою оператора new
. При цьому, фабрика сама стежить за тим, щоб створюваний продукт був потрібної варіації.
Складність:
Популярність:
Застосування: Патерн можна часто зустріти в C++ коді, особливо там, де потрібно породжувати сімейства класів, не прив’язуючи до них свій код (наприклад, у фреймворках).
Ознаки застосування патерна: Патерн можна визначити за методами, що повертають фабрику, яка, в свою чергу, використовується для створення конкретних продуктів, повертаючи їх через абстрактні типи або інтерфейси.
Концептуальний приклад
Цей приклад показує структуру патерна Абстрактна фабрика, а саме — з яких класів він складається, які ролі ці класи виконують і як вони взаємодіють один з одним.
main.cc: Приклад структури патерна
/** * Each distinct product of a product family should have a base interface. All * variants of the product must implement this interface. */ class AbstractProductA { public: virtual ~AbstractProductA(){}; virtual std::string UsefulFunctionA() const = 0; }; /** * Concrete Products are created by corresponding Concrete Factories. */ class ConcreteProductA1 : public AbstractProductA { public: std::string UsefulFunctionA() const override { return "The result of the product A1."; } }; class ConcreteProductA2 : public AbstractProductA { std::string UsefulFunctionA() const override { return "The result of the product A2."; } }; /** * Here's the the base interface of another product. All products can interact * with each other, but proper interaction is possible only between products of * the same concrete variant. */ class AbstractProductB { /** * Product B is able to do its own thing... */ public: virtual ~AbstractProductB(){}; virtual std::string UsefulFunctionB() const = 0; /** * ...but it also can collaborate with the ProductA. * * The Abstract Factory makes sure that all products it creates are of the * same variant and thus, compatible. */ virtual std::string AnotherUsefulFunctionB(const AbstractProductA &collaborator) const = 0; }; /** * Concrete Products are created by corresponding Concrete Factories. */ class ConcreteProductB1 : public AbstractProductB { public: std::string UsefulFunctionB() const override { return "The result of the product B1."; } /** * The variant, Product B1, is only able to work correctly with the variant, * Product A1. Nevertheless, it accepts any instance of AbstractProductA as an * argument. */ std::string AnotherUsefulFunctionB(const AbstractProductA &collaborator) const override { const std::string result = collaborator.UsefulFunctionA(); return "The result of the B1 collaborating with ( " + result + " )"; } }; class ConcreteProductB2 : public AbstractProductB { public: std::string UsefulFunctionB() const override { return "The result of the product B2."; } /** * The variant, Product B2, is only able to work correctly with the variant, * Product A2. Nevertheless, it accepts any instance of AbstractProductA as an * argument. */ std::string AnotherUsefulFunctionB(const AbstractProductA &collaborator) const override { const std::string result = collaborator.UsefulFunctionA(); return "The result of the B2 collaborating with ( " + result + " )"; } }; /** * The Abstract Factory interface declares a set of methods that return * different abstract products. These products are called a family and are * related by a high-level theme or concept. Products of one family are usually * able to collaborate among themselves. A family of products may have several * variants, but the products of one variant are incompatible with products of * another. */ class AbstractFactory { public: virtual ~AbstractFactory(){}; virtual AbstractProductA *CreateProductA() const = 0; virtual AbstractProductB *CreateProductB() const = 0; }; /** * Concrete Factories produce a family of products that belong to a single * variant. The factory guarantees that resulting products are compatible. Note * that signatures of the Concrete Factory's methods return an abstract product, * while inside the method a concrete product is instantiated. */ class ConcreteFactory1 : public AbstractFactory { public: AbstractProductA *CreateProductA() const override { return new ConcreteProductA1(); } AbstractProductB *CreateProductB() const override { return new ConcreteProductB1(); } }; /** * Each Concrete Factory has a corresponding product variant. */ class ConcreteFactory2 : public AbstractFactory { public: AbstractProductA *CreateProductA() const override { return new ConcreteProductA2(); } AbstractProductB *CreateProductB() const override { return new ConcreteProductB2(); } }; /** * The client code works with factories and products only through abstract * types: AbstractFactory and AbstractProduct. This lets you pass any factory or * product subclass to the client code without breaking it. */ void ClientCode(const AbstractFactory &factory) { const AbstractProductA *product_a = factory.CreateProductA(); const AbstractProductB *product_b = factory.CreateProductB(); std::cout << product_b->UsefulFunctionB() << "\n"; std::cout << product_b->AnotherUsefulFunctionB(*product_a) << "\n"; delete product_a; delete product_b; } int main() { std::cout << "Client: Testing client code with the first factory type:\n"; ConcreteFactory1 *f1 = new ConcreteFactory1(); ClientCode(*f1); delete f1; std::cout << std::endl; std::cout << "Client: Testing the same client code with the second factory type:\n"; ConcreteFactory2 *f2 = new ConcreteFactory2(); ClientCode(*f2); delete f2; return 0; }
Output.txt: Результат виконання
Client: Testing client code with the first factory type: The result of the product B1. The result of the B1 collaborating with the (The result of the product A1.) Client: Testing the same client code with the second factory type: The result of the product B2. The result of the B2 collaborating with the (The result of the product A2.)