c++ - 对象工厂中的类型映射

标签 c++ types factory

假设我有两组关联类型,例如 Animal 及其 Offspring:

/* Animal types */
struct Animal
{
  virtual string getType() const = 0;
};

struct Cat : public Animal
{
  virtual string getType() const { return "Cat"; }
};

struct Dog : public Animal
{
  virtual string getType() const { return "Dog"; }
};


/* Offspring types */
struct Offspring
{
  virtual string getType() const = 0;
};

struct Kitten : public Offspring
{
  virtual string getType() const { return "Kitten"; }
};

struct Puppy : public Offspring
{
  virtual string getType() const { return "Puppy"; }
};

我正在尝试实现一个工厂,给定一个 Animal 将返回一个关联的 Offspring 类型的对象(例如,如果 Animal实际上是一个Dog,工厂将返回一个Puppy)。

我第一次尝试实现这样的工厂是这样的:

// First attempt at OffspringFactory
class OffspringFactory1
{
  static Offspring* createKitten() { return new Kitten(); }
  static Offspring* createPuppy()  { return new Puppy();  }

public:
  // Create an Offspring according to the Animal type
  static Offspring* getOffspring(const Animal& a)
  {
    // Static mapping of Animal types to Offspring factory functions
    static map<string, Offspring* (*)()> factoryMap;
    if (factoryMap.empty())
    {
      factoryMap["Dog"] = &createPuppy;
      factoryMap["Cat"] = &createKitten;
    }

    // Lookup our Offspring factory function
    map<string, Offspring* (*)()>::const_iterator fnIt = factoryMap.find(a.getType());
    if (fnIt != factoryMap.end())
      return fnIt->second();
    else
      throw "Bad animal type";
  }
};

它工作正常,但我求助于基于字符串的映射,而不是纯粹基于类型的映射。在尝试转向更基于类型的实现时,我得出了这个结论:

// Second attempt at OffspringFactory
class OffspringFactory2
{
  // Mapping Animal types to Offspring types
  template<typename TAnimal> struct OffspringMapper;

  template<>
  struct OffspringMapper<Cat> {
    typedef Kitten offspring_type;
  };

  template<>
  struct OffspringMapper<Dog> {
    typedef Puppy offspring_type;
  };

  // Factory method
  template<typename TAnimal>
    static Offspring* create() { return new OffspringMapper<TAnimal>::offspring_type(); }

public:
  // Create an Offspring according to the Animal type
  static Offspring* getOffspring(const Animal& a)
  {
    // Static mapping of Animal type strings to Offspring factory functions
    static map<string, Offspring* (*)()> factoryMap;
    if (factoryMap.empty())
    {
      factoryMap["Dog"] = &create<Dog>;
      factoryMap["Cat"] = &create<Cat>;
    }

    // Lookup our Offspring factory function
    map<string, Offspring* (*)()>::const_iterator fnIt = factoryMap.find(a.getType());
    if (fnIt != factoryMap.end())
      return fnIt->second();
    else
      throw "Bad animal type";
  }
};

坦率地说,我不确定我在这里有什么改进:我仍然有我的字符串映射,以及更多行可读性较差的代码......

与第一个相比,第二个实现有什么优点吗?有什么方法可以去掉那个 map ?

最佳答案

这看起来像是双重 dispatch 的经典案例。在 C++ 中解决此问题的一种模式是 Visitor pattern .

class Offspring;
class OffspringFactory;

class Animal {
public:
    // ... rest of Animal class ...

    virtual Offspring* acceptOffspringFactory(OffspringFactory& factory)const = 0;
};

class OffspringFactory {
public:
    Offspring* createCatOffspring()
    {
        return new Kitten;
    }

    // ... one createXOffspring() for each type of Animal

    Offspring* getOffspring(const Animal& a)
    {
        return a.acceptOffspringFactory(*this);
    }
};

Offspring* Cat::acceptOffspringFactory(OffspringFactory& factory)const
{
    return factory.createCatOffspring();
}

// etc for rest of Animal classes

现在我再次查看你的问题,你没有指出工厂是抽象的,所以如果你可以添加像 @MooingDuck 提到的方法,你真的可以完全取消工厂。

关于c++ - 对象工厂中的类型映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7853384/

相关文章:

c++ - 在 OpenCV 应用程序中,如何确定内存泄漏的来源并修复它?

c++ - typename c++ 和编译顺序

types - 在闭包中使用多个方法构造函数,以及错误 "syntax: local variable T cannot be used in closure declaration"

TypeScript - 特定的字符串类型

c# - 为什么从针对任何 CPU 的 C# 项目调用时,此代码会抛出 System.AccessViolationException?

c++ - #pragma pack 在 C++ 中

c - 如何检查双*数组?

C# - 程序员面试挑战 - 接口(interface)和模式编程

javascript - angularjs 在不同文件中为同一模块定义服务

design-patterns - 在单元测试中使用工厂/抽象工厂设计模式