我花了大约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。)我不想在对象中设置属性,而是使用初始化列表。如果我做前者,我可以检查构造函数中的数组,根本不需要工厂。
答案 0 :(得分:1)
基本上有三种选择:
每个人都可以自由指定Enemy
的初始名称和健康状况,它在其(公共)构造函数中同时接受这两个参数。
Enemy
类构造函数将'Enemy ID'映射到属性的相应值。当您需要验证“敌人ID”的有效性和/或映射的存在时,此方法中存在的问题,同时还使用属性的初始化列表。这通常通过添加虚拟成员/基类来解决,该虚拟成员/基类通过调用验证函数来初始化
这通常如下所示:
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;
};
Enemy
对象的属性之间的映射。无需单独的工厂类。为此,工厂方法就足够了:
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
你说属性设定的数量和类型是相同的,它们只是从敌人到敌人。另一种方法是拥有一个以通用方式设置敌人属性的基类(假设_property
是Properties
的成员且可访问):
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