gpt4 book ai didi

c++ - 从结构数据继承

转载 作者:太空狗 更新时间:2023-10-29 21:04:17 24 4
gpt4 key购买 nike

想象一下下面的情况:

我想创建各种怪物工厂。这些怪物工厂根据 struct 数组提供的数据创建怪物。怪物仅在这些统计数据上有所不同,因此为每个怪物创建一个子类是多余的。

struct monster_data
{
int HP;
int strength;
int speed;
// even more attributes
};

monster可以根据monster_data处理怪物的所有行为:

class monster
{
public:
monster(monster_data* initial_stats, int length);

void attack();
void walk();
void die();
// and so forth
};

到目前为止,还不错。现在我有一个类 monster_factory,它根据硬编码的 monster_data 数组创建怪物:

const monster_data district1_monsters[]
{
{ 500, 20, 4 }, // monster1
{ 550, 5, 12 }, // monster2
{ 420, 8, 10 }, // monster3
{ 310, 30, 7 }, // monster4
// 100 more monsters
};

class monster_factory
{
public:
monster_factory(monster_data* monster_to_create) ;
monster* create_random_monster();
};

我的问题是我必须为几个地区支持多个 monster_factories,列表中的差异很小:

const monster_data district1_monsters[]
{
{ 500, 20, 4 }, // monster1
{ 550, 5, 12 }, // monster2
{ 420, 8, 10 }, // monster3
{ 310, 30, 7 }, // monster4
// 100 more monsters
};

const monster_data district2_monsters[]
{
{ 500, 20, 4 }, // monster1
{ 750, 5, 12 }, // MONSTER2B <<
{ 420, 8, 10 }, // monster3
{ 310, 30, 7 }, // monster4
// monsters 5 - 80 from district 1
};

const monster_data district3_monsters[]
{
{ 500, 20, 4 }, // monster1
{ 550, 5, 12 }, // monster2
{ 720, 80, 10 }, // MONSTER3B <<
{ 310, 30, 7 }, // monster4
// monsters 8 - 90 from district 1
};

我不想复制和粘贴数组数据,而是想以某种方式继承它,因为数据在不同版本之间基本保持相同。复制整个 struct 数组声明只是为了有一个稍微不同的变体似乎是错误的方法。遗憾的是 2 区和 3 区只是附加数据,它们修改并省略了现有条目。当然,他们也改变了不止一种怪物。

此外,第 1 区怪物数据的更改也应适用于第 2 区和第 3 区。

另一个问题是,有些地区会拥有与1、2、3区完全无关的怪物数据。

const monster_data district4_monsters[]
{
{ 100, 20, 10 }, // monster 401
{ 200, 50, 20 }, // monster 402
{ 300, 40, 5 }, // monster 403
{ 400, 30, 30 }, // monster 404
// 20 more monsters unrelated to district 1,2 & 3
};

现在问题:如何更改概述的设计,以避免冗余的 monster_data 声明,并且可以添加派生其 的地区来自现有声明的 monster_data 还是使用全新的声明?

奖励积分,如果您的设计确保怪物统计列表的每个变体只能有一个工厂实例。

最佳答案

这可以通过 decorator pattern 优雅地解决通过用每一层的变化装饰“默认”表:

class MonsterTable
{
public:
virtual monster_data const* getMonsterForIndex(int i)=0;
};

class DefaultMonsterTable : public MonsterTable
{
public:

monster_data const* getMonsterForIndex(int i)
{
return district1_monsters+i;
}
};

class OverlayMonsterTable : public MonsterTable
{
public:
//public for brevity, should be private in real code - can also be std::map
std::unordered_map<int, monster_data> OverlayData;

// Init this with the "previous layer", which is always the Default table in your examples
MonsterTable* Decorated;

monster_data const* getMonsterForIndex(int i)
{
typedef std::unordered_map<VGLindex, monster_data>::const_iterator Iterator;
Iterator Overlay=OverlayData.find(i);
if (Overlay!=OverlayData.end()) // Monster data was changed in this layer
return &Overlay->second;

return Decorated->getMonsterFromIndex(i); // Defer to next layer
}
};

然后,您可以将较高地区的所有“更改”添加到 OverlayData,并让 OverlayMonsterTable 引用默认表 (district1)。

为了支持省略数据,您可以添加另一个重新映射索引的装饰器“层”(例如,将 [0...80] 映射到 [0...10]、[30...100]) ,或将此功能集成到现有的 OverlayMonsterTable 中。无论哪种方式,您都拥有充分的灵 active 。例如:

class OmitMonsterTable : public MonsterTable
{
public:
int OmitBegin, OmitEnd;
MonsterTable* Decorated;

monster_data const* getMonsterForIndex(int i)
{
if (i > OmitBegin)
i += OmitEnd;

return Decorated->getMonsterForIndex(i);
}
};

你的工厂只需要一个 MonsterTable 指针/引用。

关于c++ - 从结构数据继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11537155/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com