C++ 抽象工厂模式怎么用?如何实现 Abstract Factory Pattern?

文章导读
Previous Quiz Next Abstract Factory 是一种 创建设计模式,它提供了一个 interface,包含创建特定类型对象的方法,但允许 subclasses 来改变将被创建的对象类型。Abstract Factory 模式 用于我们有 多个
📋 目录
  1. C++ 中 Abstract Factory 模式的实现
  2. C++ 中的传统 Abstract Factory 实现
  3. C++ 中的基于 Registry 的 Abstract Factory 实现
  4. Abstract Factory Pattern 的优点和缺点
  5. 何时使用 Abstract Factory Pattern?
  6. Conclusion
A A

C++ 中的 Abstract Factory 设计模式



Previous
Quiz
Next

Abstract Factory 是一种 创建设计模式,它提供了一个 interface,包含创建特定类型对象的方法,但允许 subclasses 来改变将被创建的对象类型。Abstract Factory 模式 用于我们有 多个 families 的相关或依赖对象,并且希望在不指定其 concrete classes 的情况下创建它们。

换句话说,它是一个 工厂的工厂。在上一个章节中,我们讨论了 Factory Method 模式,它用于创建 单个 family 的对象。但在 Abstract Factory 模式 中,我们可以创建 多个 families 的对象。

想象你正在建造你的梦想房子,你有两种家具选择:ModernVictorian。每种类型都有自己匹配的一套物品,如 chairsofacoffee table。与其一件一件挑选物品并可能造成风格不搭配,不如使用一个 furniture factory,它一次性提供整套同一风格的物品。如果你想要 Modern,你就得到所有 Modern 物品。如果你想要 Victorian,你就得到所有 Victorian 物品。Abstract Factory 模式 的工作方式相同:它提供一整套同一风格的相关对象,确保一切完美契合。

C++ 中 Abstract Factory 模式的实现

以下是在 C++ 中实现 Abstract Factory 模式的一些重要方式:

  • Conventional Abstract Factory − 它使用经典的 interfaceconcrete factories
  • Registry-based Abstract Factory − 它使用 registry of factories 来创建 不同 families 的对象。

Concrete Factory 是一个实现了 Abstract Factory interface 的 class,负责创建特定 family 的对象。client code 使用 abstract factory interface 来创建对象,而无需知道具体的类。

C++ 中的传统 Abstract Factory 实现

在这种方法中,我们创建一个 abstract factory interface,用于定义创建 family of related objects 的方法。然后,我们创建 concrete factory classes,它们实现 abstract factory interface,并提供创建 particular family 对象的实现。

C++ 中 Abstract Factory Pattern 示例

在下面的示例中,我们有一个 abstract factory interface FurnitureFactory,它定义了创建 family of related objects 的方法。我们有两个 concrete factory classes ModernFurnitureFactoryVictorianFurnitureFactory,它们实现 FurnitureFactory interface,并提供创建 particular family 对象的实现。客户端代码使用 abstract factory interface 创建对象,而无需知道具体的类。

Abstract Factory Pattern in C++

让我们在 C++ 中实现一个简单的 Abstract Factory Pattern 示例

#include <iostream>
#include <string>
using namespace std;

// Abstract Product A
class Chair {
   public:
      virtual string getType() = 0;
};

// Abstract Product B
class Sofa {
   public:
      virtual string getType() = 0;
};

// Concrete Product A1
class ModernChair : public Chair {
   public:
      string getType() {
         return "Modern Chair";
      }
};

// Concrete Product B1
class ModernSofa : public Sofa {
   public:
      string getType() {
         return "Modern Sofa";
      }
};

// Concrete Product A2
class VictorianChair : public Chair {
   public:
      string getType() {
         return "Victorian Chair";
      }
};

// Concrete Product B2
class VictorianSofa : public Sofa {
   public:
      string getType() {
         return "Victorian Sofa";
      }
};

// Abstract Factory
class FurnitureFactory {
   public:
      virtual Chair* createChair() = 0;
      virtual Sofa* createSofa() = 0;
};

// Concrete Factory 1
class ModernFurnitureFactory : public FurnitureFactory {
   public:
      Chair* createChair() {
         return new ModernChair();
      }
      Sofa* createSofa() {
         return new ModernSofa();
      }
};

// Concrete Factory 2
class VictorianFurnitureFactory : public FurnitureFactory {
   public:
      Chair* createChair() {
         return new VictorianChair();
      }
      Sofa* createSofa() {
         return new VictorianSofa();
      }
};

int main() {
   FurnitureFactory* factory;
   Chair* chair;
   Sofa* sofa;

   // Create Modern Furniture
   factory = new ModernFurnitureFactory();
   chair = factory->createChair();
   sofa = factory->createSofa();
   cout << "Created the Modern furniture:" << endl;
   cout << "Chair: ";
   cout << chair->getType() << endl;
   cout << "Sofa: ";
   cout << sofa->getType() << endl;

   // Create Victorian Furniture
   factory = new VictorianFurnitureFactory();
   chair = factory->createChair();
   sofa = factory->createSofa();
   cout << "Created the Victorian furniture:" << endl;
   cout << "Chair: ";
   cout << chair->getType() << endl;
   cout << "Sofa: ";
   cout << sofa->getType() << endl;

   return 0;
}

以下是上述程序的输出 −

Created the Modern furniture:
Chair: Modern Chair
Sofa: Modern Sofa
Created the Victorian furniture:
Chair: Victorian Chair
Sofa: Victorian Sofa

C++ 中的基于 Registry 的 Abstract Factory 实现

这是我们在 Factory Method pattern 中讨论过的一种类似方法。在这种方法中,我们创建一个工厂的 registry,它可以创建不同 family 的对象。Registry 是一个map,它将family name 映射到对应的factoryClient code 使用 registry 获取特定 family 的 factory,然后使用该 factory 创建对象。

C++ 中基于 Registry 的 Abstract Factory Pattern 示例

让我们以汽车工厂为例。我们有一个抽象类 CarFactory,它定义了工厂方法 createCar()。然后,我们创建具体的子类,如 SUVFactorySedanFactory,它们实现了工厂方法来创建特定类型的汽车。我们还创建了一个工厂的 registry,将 family name 映射到对应的 factory。

Registry-based Abstract Factory Pattern in C++

以下是 C++ 中基于 Registry 的 Abstract Factory Pattern 的简单示例

#include <iostream>
#include <string>
#include <map>

using namespace std;

// Product interface  // 产品接口
class Car {
   public:
      virtual string getType() = 0;
};

// Concrete Products  // 具体产品
class SUV : public Car {
   public:
      string getType() {
         return "SUV";
      }
};

class Sedan : public Car {
   public:
      string getType() {
         return "Sedan";
      }
};

// Factory interface  // 工厂接口
class CarFactory {
   public:
      virtual Car* createCar() = 0;
};

// Concrete Factories  // 具体工厂
class SUVFactory : public CarFactory {
   public:
      Car* createCar() {
         return new SUV();
      }
};

class SedanFactory : public CarFactory {
   public:
      Car* createCar() {
         return new Sedan();
      }
};

// Registry of factories  // 工厂的 registry
class CarFactoryRegistry {
   private:
      map<string, CarFactory*> registry;
   public:
      void registerFactory(string type, CarFactory* factory) {
         registry[type] = factory;
      }
      CarFactory* getFactory(string type) {
         return registry[type];
      }
};
int main() {
   CarFactoryRegistry registry;
   registry.registerFactory("SUV", new SUVFactory());
   registry.registerFactory("Sedan", new SedanFactory());

   CarFactory* factory;
   Car* car;

   // Create SUV  // 创建 SUV
   factory = registry.getFactory("SUV");
   car = factory->createCar();
   cout << "Created car of type: ";
   cout << car->getType() << endl;

   // Create Sedan  // 创建 Sedan
   factory = registry.getFactory("Sedan");
   car = factory->createCar();
   cout << "Created car of type: ";
   cout << car->getType() << endl;

   return 0;
}

以下是上述程序的输出 −

Created car of type: SUV
Created car of type: Sedan

Abstract Factory Pattern 的优点和缺点

以下是 Abstract Factory Pattern 的一些重要优点和缺点 −

优点 缺点
使匹配对象组易于创建,无需担心细节。 会使代码变大且更复杂,因为需要额外的工厂类。
保持代码灵活,便于轻松切换对象 family。 如果有多个对象 family,则类数量很多
易于添加新的对象 family,无需更改旧代码。 更新和维护所有工厂的工作量更大
确保一切匹配,不会出现混搭错误。 对于简单情况过于复杂,一个工厂就足够了。

何时使用 Abstract Factory Pattern?

以下是一些可以使用 Abstract Factory Pattern 的重要场景 −

  • 当系统需要独立于其产品如何被创建组合表示时。
  • 当系统使用多个 family 中的一个配置产品 family 时。
  • 当我们想提供一个产品库,并且只想暴露它们的interfaces,而不是implementations时。
  • 当我们想确保client code 只使用来自同一 family 的对象时。

Conclusion

Abstract Factory 是一种 creational 软件设计模式,它提供了一个 interface,用于生成相关或依赖对象的家族,而无需暴露它们的 concrete classes。当我们有多个家族的相关或依赖对象,并且希望在不定义它们的 concrete classes 的情况下创建它们时,就会使用它。Abstract Factory pattern 隐藏了对象的构造过程,并为 concrete classes 和客户端代码提供了loose binding,同时它还满足了 Open/Closed Principle,因为可以在不修改代码的情况下添加新的相关对象家族。