2016-11-25 38 views
2

我需要解析XML并在C++中创建对应于XML元素的对象,并将XML元素的属性作为属性打包到这些对象中。 XML元素/属性和相应的C++类/属性继承自具有派生对象通用属性的基础对象。多态性或属性字典?

我正在考虑使用基类的公共属性和派生类只需要定义对象的特定属性。然而,有人告诉我,使用标准多态不是一个好主意,因为解决方案不够通用 - 在XML中添加/更改属性需要向C++类添加/更改相应的属性,这需要更改太多的代码。一个更好更抽象的解决方案是将一个属性字典放在基类中,并通过搜索字典来访问各个属性。我想问社区这个建议是否对生产代码更好。

下面是一个例子,其中车辆是基础对象,并且不同的车辆类型从它继承。 车辆物体具有所有车辆通用的nameweight属性。下面是一个示例XML片段:

<car name="Toyota" weight="3500" passengers="4" /> 
<boat name="Yamaha" weight="3700" draft="16" /> 

基类:

class vehicle { 
    public: 
    string name; 
    string weight; 
}; 

派生类:

class car : public vehicle { 
    public: 
    string passengers; 
}; 

class boat : public vehicle { 
    public: 
    string draft; 
}; 

现在,当我的解析器发现汽车和船的元素我实例:

boat *b = new boat(); 
car *c = new car(); 

对于我可以简单地访问所有成员b->name,b->weightb->draft。在C++对象从XML实例化后,我们在每个属性上完成了大量针对对象的工作,因此我们的目标不是简单地将XML加载到程序中。

另一种方法:

#define TAG_XML_ATTRIBUTE_NAME    "name" 
#define TAG_XML_ATTRIBUTE_WEIGHT   "weight" 
#define TAG_XML_ATTRIBUTE_PASSENGERS  "passengers" 
#define TAG_XML_ATTRIBUTE_DRAFT    "draft" 
. . . 

class vehicle { 
    public: 
    map<string, string> arguments; 

    // Get argument by name searching the arguments dictionary. 
    string GetArgumentOrEmpty(const string& argumentName); 
}; 

class car : public vehicle { 
    public: // All propeties are in the base class dictionary. 
}; 

class boat : public vehicle { 
    public: // All propeties are in the base class dictionary. 
}; 

所有派生类具有arguments图;为了得到属性值,我们扫描词典以按名称查找属性,然后读取它的值,例如, GetArgumentOrEmpty(TAG_XML_ATTRIBUTE_WEIGHT)。现在的CPU速度很快,因此搜索字典不会明显影响性能。元素/属性的命名空间从结构化(作为类成员)到平坦(作为#define列表),但它们将全部位于同一位置。代码更抽象;尽管对象处理代码由于额外的间接寻址而变得更加复杂,但如果属性名称更改,则不需要更改;例如如果在XML改变peoplepassengers,#定义会显得有点尴尬,但使用它不会有更改代码:

#define TAG_XML_ATTRIBUTE_PASSENGERS  "people" 

是否基于字典的属性访问方法存在足够的好处将其用于生产代码而不是使用常规的类属性?如果是这样,是仅仅为了这个特定的XML解析情况还是用字典搜索替换多态性并用字符串名称替换类属性通常是一个更好的主意?

回答

1

的基于字典的方法确实有几个优点:

  • 可以很容易地新新属性添加到一个类/对象。
  • 对象加载/保存/创建代码将是非常通用的。
  • 这有可能使属于类完全可配置的属性
  • 事实上,一些游戏编码专家,如Mike McShaffry(“Game Coding Complete”)主张用这样一种‘组件’架构为代表的游戏角色,而不是深层次的继承层次,这些层次更难维护和丰富。

有一对夫妇的不便,以及:

  • 类特殊处理代码将与干将
  • 被堆满此代码将在很大程度上取决于物业的命名,这使得可配置不太容易。
  • 由于未被注意到的拼写错误,很容易将错误导入系统:编译器不会发现这些不一致,因为它只是临时数据。

所以你必须做出艰难的选择。我的建议是:

  • 如果您有复杂的类相关处理代码,那么它会很容易出错,坚持您的原始方法。知道你正在使用的成员变量的编译器的好处是可靠性的保证。
  • 如果您只有几个与类相关的例程,并且属性大多是描述性的并以类似的方式处理,那么如果您需要易于扩展和可配置的对象结构,则采用地图方法
  • 是有意义的,第二种方法也是更灵活的方法。

如果你去的地图,一对夫妇的想法:

  • 你能想到的外部属性的名称和内部整数相当于代表它之间的字典。这将避免大量的字符串处理开销,从而加速地图。
  • 你可以设想使用unordered_map来避免太多的字符串比较。
+0

Christophe,你能否请你完成你的想法“事实上,一些游戏编码专家,比如......” - 这里的细节非常有价值。 – sun2sirius

+0

@ sun2sirius对不起,在写作过程中,这句话被切断了,并失去了。我编辑完成了这个句子。 – Christophe