参数化类创建与断言if参数存在。使用工厂?

时间:2010-11-11 15:26:17

标签: c++ function static initialization factory

我花了大约2个小时阅读了很多与工厂相关的主题,但我仍然不确定这是否是正确的方法。

事情就是这样:我有一个 Enemy 类,其中包含 name _和 health _等成员变量。我想用这些成员变量的不同值创建它的实例,我的第一种方法是从具有属性的静态数组中获取参数:

Enemy::Enemy(int type) : name_(properties[type].name),
                             health_(properties[type].health)
{
...
}

这里的问题是我无法检查数组属性是否已经填充。我必须通过调用静态 Enemy :: initArray()函数从外部检查它,但这会破坏 Enemy 类的封装。

是时候创建一个工厂来初始化它的构造函数中的属性数组了吗?然后用:

制造敌人
Enemy* EnemyFactory::create(type);

我读到,通常在具有复杂的类层次结构时创建工厂,或者工厂调用者只需要知道所创建的类的接口。我只需要封装数组创建和验证。是否有“更轻”的解决方案?

修改 我会试着更清楚:

1。)我想我知道如何来创建工厂。主要问题是是否存在替代

2。)我不想在对象中设置属性,而是使用初始化列表。如果我做前者,我可以检查构造函数中的数组,根本不需要工厂。

4 个答案:

答案 0 :(得分:1)

基本上有三种选择:

  1. 每个人都可以自由指定Enemy的初始名称和健康状况,它在其(公共)构造函数中同时接受这两个参数。

  2. Enemy类构造函数将'Enemy ID'映射到属性的相应值。当您需要验证“敌人ID”的有效性和/或映射的存在时,此方法中存在的问题,同时还使用属性的初始化列表。这通常通过添加虚拟成员/基类来解决,该虚拟成员/基类通过调用验证函数来初始化 这通常如下所示:

  3.     class Enemy
        {
            bool dummy_must_be_first;
        public:
            Enemy(int type) : dummy_must_be_first(validate(type), name(properties[type].name), health(properties[type].health) {}
    
        private:
            bool validate(int type)
            {
                // ensure properties is initialised and verify type is within range...
                // on failure, throw an exception
    
                return true;
            }
    
            string name;
            int health;
        };
    
    1. 您使用工厂函数执行“敌人ID”与用于初始化Enemy对象的属性之间的映射。
    2. 无需单独的工厂类。为此,工厂方法就足够了:

      class Enemy
      {
      private:
          Enemy(string name_, int health_) : name(name_), health(health_) {}
      
          string name;
          int health;
      public:
          static auto_ptr<Enemy> createEnemy(int type)
          {
              // ensure properties is initialised and verify type is within range...
      
              return auto_ptr<Enemy>(new Enemy(properties[type].name, properties[type].health));
          }
      };
      

答案 1 :(得分:0)

我看到两种可能性。

name_(default_name_value), health_(default_health_value)然后在构造函数体中进行实际分配

使用构造方法

答案 2 :(得分:0)

您的工厂会参考物业。 敌人应该在其构造函数中将name和health作为参数。

然后像:

Enemy* EnemyFactory::create(int type) const
{
   return new Enemy( properties[type].name, properties[type].health );
}

如果找不到这些属性,则需要通过抛出相应的错误消息或允许默认值来处理这种情况。

答案 3 :(得分:0)

建议1

介绍EnemyCreator怎么样?

class EnemyCreator
{
protected:
    Enemy* createImpl() const = 0;

public:
    // ctors

    Enemy* create() const
    {
        return(createImpl());
    }; // eo create
};  // eo class EnemyCreator


// a concrete creator

class EnemyType1Creator : public EnemyCreator
{
protected:

    Enemy* createImpl() const
    {
        Properties p;
        // ...
        // fill in properties here
        //
        return new Enemy(p); // Enemy will populate
    };
}; // eo class EnemyType1Creator

然后修改您的EnemyFactor以管理一堆EnemyCreator对象。

建议2

你说属性设定的数量和类型是相同的,它们只是从敌人到敌人。另一种方法是拥有一个以通用方式设置敌人属性的基类(假设_propertyProperties的成员且可访问):

class EnemyProperties : public Properties
{
protected:
    virtual void initialiseImpl() = 0;

public:
    void initialise()
    {
        // set up the properties all enemies have
        _property["healh"] = 5;
        _property["skill"] = 0.5f;
        _property["skillWithABanana"] = 1.0f;

        // now let derived classes specialise
        initialiseImpl();
    };
}; // eo class EnemyProperties

现在我们可以为任意数量的类型创建属性集,只改变我们想要的内容:

class BadBananaEnemy : public EnemyProperties
{
protected:
    void initialiseImpl()
    {
        _property["skillWithABanana"] = 0.0f; // he's bad at this.
    }; // eo initialiseImpl()
}; // eo class BadBananaEnemy

etceteras。

然后你可以将它们放在一个可以通过名字输出这些产品的工厂中:

class EnemyFactory
{
private:
    typedef std::pair<std::string, EnemyProperties> EnemyPair;
    typedef std::map<std::string, EnemyProperties> EnemyMap;
    EnemyMap m_EnemyTypes;

public:
    // register a type
    void registerType(const std::string& _name, const EnemyProperties& _prop)
    {
        m_EnemyTypes.insert(EnemyPair(_name, _prop));
    }; // eo registerType

    // create an enemy
    Enemy* createEnemy(const std::string& _type)
    {
        EnemyMap::iterator it(m_EnemyTypes.find(_type));
        if(it != m_EnemyTypes.end())
            return(NULL);
        else
            return(new Enemey(it->second));
    }; // eo createEnemy
}; // eo class EnemyFactory