C++ 工厂模式实现 - 示例、问题和疑虑

标签 c++ factory-pattern

最近我一直在尝试更好地理解在 C++ 中使用工厂模式。

我引用了以下资源:

How to implement the factory method pattern in C++ correctly

https://www.geeksforgeeks.org/design-patterns-set-2-factory-method/

https://sourcemaking.com/design_patterns/factory_method/cpp/1

https://www.codeproject.com/Articles/363338/Factory-Pattern-in-Cplusplus

https://www.bogotobogo.com/DesignPatterns/factorymethod.php

https://gist.github.com/pazdera/1099562

https://en.wikibooks.org/wiki/C%2B%2B_Programming/Code/Design_Patterns

在有人将此标记为“不是问题”之前,我确实有一些明确的问题,我稍后会谈到。但为了澄清我到目前为止的理解,我想先从一个例子开始。这是我能够根据上述链接中的信息做出的最佳示例(最佳含义说明了工厂模式,但尽可能简单,因此该模式的初学者可以清楚地看到所涉及的问题):

// FactoryPattern.cpp

#include <iostream>
#include <vector>

enum AnimalSpecies { dog, cat };


class Animal
{
public:
  virtual void makeSound() = 0;
};

class Dog : public Animal
{
public:
  void makeSound() { std::cout << "woof" << "\n\n"; }
};

class Cat : public Animal
{
public:
  void makeSound() { std::cout << "meow" << "\n\n"; }
};

class AnimalFactory
{
public:
  static Animal* makeAnimal(AnimalSpecies animalSpecies);
};

Animal* AnimalFactory::makeAnimal(AnimalSpecies animalSpecies)
{
  if (animalSpecies == AnimalSpecies::dog)
  {
    return(new Dog());
  }
  else if (animalSpecies == AnimalSpecies::cat)
  {
    return(new Cat());
  }
  else
  {
    std::cout << "error in AnimalFactory::makeAnimal(), animalSpecies = " << animalSpecies << " does not seem to be valid" << "\n\n";
    return(nullptr);
  }
}

int main(void)
{
  std::vector<Animal*> animals;

  animals.push_back(AnimalFactory::makeAnimal(AnimalSpecies::dog));
  animals.push_back(AnimalFactory::makeAnimal(AnimalSpecies::cat));

  for (auto &animal : animals)
  {
    animal->makeSound();
  }

  for (auto& animal : animals)
  {
    delete(animal);
  }

  return(0);
}

这个程序的输出(如预期的那样)是:

woof

meow

这是我现在的问题:

1) 我对工厂模式所做的一些阅读使我相信消除 if 语句是好处的一部分。上面的示例在这方面失败了,因为在 AnimalFactory::makeAnimal() 中必须使用 if-else 来确定物种。有没有办法重构它以删除 if 语句?

2) 随着最近 C++ 14/17/20 的各种变化和改进,我们中的许多人正在远离指针以避免内存泄漏的可能性。有没有办法重构它以便不使用指针?

3) 工厂模式的优势是什么?即在上面的示例中为什么不省略类 AnimalFactory 并简单地使 main() 如下:

int main(void)
{
  Dog dog;
  dog.makeSound();

  Cat cat;
  cat.makeSound();

  return(0);
}

最佳答案

has led me to believe that eliminating if statements is part of the benefit.

恕我直言,工厂模式的真正力量来自工厂模式的虚拟化:

class AnimalFactoryInterface
{
  public:
    virtual Animal* makeAnimal() = 0;
};

class CatFactory : public AnimalFactoryInterface
{
  public:
    Animal* makeAnimal() override { return new Cat(); }
};

这虚拟化了如何创造新动物,这是不可能做到的。

switch 语句构造函数对于从配置文件制作动物很有用,但这并不是这里的真正力量。它有助于创建通用 Breeder接受如何制作普通动物的类。

2) With the various changes and improvements in C++ 14/17/20 lately, many of us are moving away from pointers to avoid the possibility of memory leaks. Is there a way to refactor this so as to not use pointers?

返回智能指针(std::unique_ptr<Animal>)。

3) What is the advantage of the Factory Pattern? i.e. in the above example why not omit class AnimalFactory and simply make main() as follows:

首先,它使操作变得容易

class Breeder {
 public:
   Breeder(std::unique_ptr<AnimalFactoryInterface> animal_factory);
   void Breed() { animals_.push_back(animal_factory_->Create()); }
   // ... more stuff
 private:
   std::unique_ptr<AnimalFactoryInterface> animal_factory_;
   std::vector<std::unique_ptr<Animal>> animals_;
};

第二个是 Dependency Injection .

我们还应该弄清楚“工厂模式”。

我在这个答案中描述的是 Abstract Factory Pattern - 即利用工厂接口(interface)创建对象。

使用带有 switch 语句的单个方法来创建对象是 Factory Method Pattern .它肯定有它的实用性,但我总是发现它太明显了,不能过多地依赖于完整的“设计模式”。但是对于这个问题和优势问题来说,最重要的是,如果你所做的只是简单地制作一系列对象,那么你是对的——你绝对不需要工厂类,你甚至不需要如果您所做的只是制作一次类(class),则需要一种特殊的方法。任何编程的经验法则是做最简单的事情。

关于C++ 工厂模式实现 - 示例、问题和疑虑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56415444/

相关文章:

java - 设计模式 : Reduce duplicate code from 2 methods that is almost the same in java

C++ 推荐的 RAII 类型声明方式(unique_lock)

c++ - 在 header 中隐藏依赖项

c++ - 当 GUI 线程在 Qt 中空闲时发出信号?

java - DAO工厂 : return a new instance or always the same?

c# - 具体类位于单独的 DLL 上的工厂模式

c++ - 如何将数据传递给使用工厂方法创建的对象

java - 基于动态构造函数值的 Spring bean 作用域

c++ - 条件模板变量

c++ - 如果不是抽象则调用基类方法