C+中的通用工厂+; 我正在研究一个游戏,我试图通过分析一个文本文件来实现一个聪明的方法来创建C++中的NPC对象。

C+中的通用工厂+; 我正在研究一个游戏,我试图通过分析一个文本文件来实现一个聪明的方法来创建C++中的NPC对象。,c++,factory,C++,Factory,目前,这是在Factory对象中硬编码的。像这样: IActor * ActorFactory::create(string actortype, Room * r, string name, int hp) { if(actortype == "Troll") { return new Troll(r, name, hp); } if (actortype == "Dragon") { return new Dragon(

目前,这是在Factory对象中硬编码的。像这样:

IActor * ActorFactory::create(string actortype, Room * r, string name, int hp)
{
    if(actortype == "Troll")
    {
        return new Troll(r, name, hp);
    }
    if (actortype == "Dragon")
    {
        return new Dragon(r, name, hp);
    }
    // ... and so on
    throw "Can't recognize type '"+actortype+"'.";
}
在我看来,这是一种非常丑陋的做法。因为它(除其他外)打破了传统

我学的是Java,在Java中,我会做一些事情,比如让每个IActor在程序执行开始时向ActorFactory报告它的类名和类类型。然后,工厂将关系存储在一个映射中,然后可以轻松地查找哪些字符串映射到哪个对象,然后可以轻松地实例化它

编辑:我还希望能够使用可变数量/类型的参数调用构造函数


<>强> C++中如何做到这一点?可以这样做吗?

您可以使用映射来存储返回Actor*的函数指针,该指针是指向所创建对象的指针。那么代码就是

std::map<std::string,IActor* (*) (Room*,std::string,int)> constructorMap    
constructorMap["Troll"]=&TrollConstructor
//etc...
IACtor* ActorFactory::create(string actortype,Room* r,string name,int hp){
  return (*constructorMap[actortype])(r,name,hp);
}
std::映射构造函数映射
constructorMap[“Troll”]=&TrollConstructor
//等等。。。
IACtor*ActorFactory::create(字符串actortype,房间*r,字符串名称,int-hp){
return(*constructorMap[actortype])(r,name,hp);
}

< P>(请原谅我用函数指针做的任何错误,它们不是我的优点)C++中的

< P>,你通常会使用抽象工厂设计模式。 要点是:“关于要创建的参与者类型的决定不应该由
ActorFactory::create()
负责”。在您的情况下,此方法不应该基于字符串决定实例化哪个类,而应该依赖于类型;此类型是实际的factory类

  • 每个actor类都有自己的工厂类:
    TrollFactory
    DragonFactory
    ,等等。这些工厂类派生自一个基类
    ActorFactory2
    (后面的2是因为
    ActorFactory

  • 每个专门的工厂类实现一个虚拟的
    create()
    方法,而无需参数返回指向新创建的actor类的指针

  • 如果需要参数来构造actor,请在创建actor之前将其传递给factory对象:将其传递到actor中,并将其存储为成员变量<代码>创建()将在稍后创建参与者时检索它们

  • 通过这种方式,您可以轻松地为不同的参与者传递不同的参数,并且您的工厂机制将是可伸缩的(朝着开放/封闭原则迈出的一步)

  • 现在,
    ActorFactory::create()
    接受一个指向从
    ActorFactory2
    派生的对象的指针,并调用
    ActorFactory2::create()
    方法:它将使用适当的参数创建请求的actor,而不使用switch语句

    class ActorFactory2
    {
      string m_name; // Each IA actor has a name
      int m_hp;      // and some HP
    public:
      ActorFactory2( const string &p_name, int p_hp )
        : m_name( p_name ), m_hp( p_hp ) {}
      virtual IActor * create() const = 0;
    };
    
    class TrollFactory : public ActorFactory2
    {
      // No special argument needed for Troll
    public:
      TrollFactory( const string &p_name, int p_hp )
        : ActorFactory2( p_name, p_hp ) {}
      virtual IActor * create() const { return new Troll( m_name, m_hp ); }
    };
    
    class DragonFactory : public ActorFactory2
    {
      FlameType m_flame; // Need to indicate type of flame a dragon spits
    public:
      DragonFactory( const string &p_name, int p_hp, const FlameType &p_flame )
        : ActorFactory2( p_name, p_hp )
        , m_flame( p_flame ) {}
      virtual IActor * create() const { return new Dragon( m_name, m_hp, m_flame ); }
    };
    
    IActor * ActorFactory::create( const ActorFactory2 *factory )
    {
      return factory->create();
    }
    
    int main( int, char ** )
    {
      ActorFactory af;
      ...
      // Create a dragon with a factory class instead of a string
      ActorFactory2 *dragonFactory = new DragonFactory( "Fred", 100, RedFlames );
      IActor *actor = af.create( dragonFactory ); // Instead of af.create( "dragon", ... )
      delete dragonFactory;
    }
    

  • 我在另一个关于C++工厂的问题上回答了问题。请看是否有兴趣建立一个灵活的工厂。我试图描述一种从ET++到使用宏的老方法,这种方法对我来说非常有效


    是将旧Mac App移植到C++和X11的项目。在it的努力中,Eric Gamma等开始考虑设计模式,具体术语是:参数化工厂方法,它是工厂方法设计模式的一部分

    要使用泛型工厂,请将类保存在映射中并通过字符串进行访问。如果类名可用,请使用“typeid(MyClass).name()将该类注册到工厂,并通过提供clone()成员函数返回该类的副本

    但是,对于简单的不可扩展工厂,我使用您问题中的方法


    我无法回答您关于传递更多变量参数的问题,但要进行反序列化,只需将部分传递给类并让它自己进行反序列化就足够了(您似乎已经这样做了)。

    感谢您的回答,但这不允许我有一个变量参数列表。(不同数量的参数和不同类型)这是有道理的,但会生成很多类(如果有很多参与者)优点是您可以将变量的变量传递给CtoR。我不知道工厂方法或抽象工厂模式有很多不同。因为在使用之前,我们仍然需要知道具体的类。在我的例子中,我需要基于配置文件中的名称实例化我的类。菲尼特正是我想要的。