多态性还是属性字典?

Polymorphism or dictionary of properties?

我需要解析一个 XML 并在 C++ 中创建对应于 XML 元素的对象,并将 XML 元素的属性作为属性打包到这些对象中。 XML elements/attributes 和相应的 C++ classes/properties 继承自具有与派生对象共有的属性的基对象。

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

下面是一个示例,其中 vehicle 是基础对象,不同的车辆类型继承自它。 Vehicle 对象具有所有车辆共有的 nameweight 属性。这是一个示例 XML 片段:

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

基础class:

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

派生 classes:

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

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

现在,当我的解析器找到我实例化的汽车和船元素时:

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

对于 boat,我可以简单地访问所有成员 b->nameb->weightb->draft。在从 XML 实例化 C++ 对象后,我们对每个 属性 执行所有特定于对象的工作,因此目标不仅仅是将 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.
};

所有派生的 classes 都有 arguments 映射;为了获得 属性 值,我们扫描字典以按名称查找 属性 ,然后读取其值,例如GetArgumentOrEmpty(TAG_XML_ATTRIBUTE_WEIGHT)。现在的 CPU 很快,所以搜索字典不会明显影响性能。 elements/attributes 的命名空间从结构化(如 class 成员)变为扁平化(如 #define 列表),但它们都在一个地方。代码更抽象;虽然对象处理代码由于额外的间接寻址而变得更加复杂,但如果属性名称发生变化则不需要更改;例如如果XML中的passengers改为people,#define看起来会有点别扭,但是使用它的代码不用改:

#define TAG_XML_ATTRIBUTE_PASSENGERS        "people"

基于字典的 属性 访问方法是否具有足够的优势以将其用于生产代码而不是使用常规 class 属性?如果是这样,是否仅针对这种特定的 XML 解析情况或用字典搜索替换多态性并用字符串名称替换 class 属性通常是更好的主意?

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

  • 向 class/object 添加新属性很容易。
  • 对象 loading/saving/creation 代码非常通用。
  • 可以使属于 class 的属性完全可配置
  • 事实上,一些游戏编码专家,例如 Mike McShaffry ("Game Coding Complete") 提倡使用这种 "Component" 架构来表示游戏参与者,而不是使用深度继承层次结构更难维护和丰富。

还有一些不便之处:

  • class 特定的处理代码会被 getter 弄得乱七八糟
  • 此代码在很大程度上取决于 属性 命名,这使得可配置性变得不那么容易。
  • 由于未注意到的打字错误很容易将错误引入系统:编译器不会发现这些不一致,因为它只是垃圾数据。

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

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

如果你想要地图,有几点想法:

  • 您可以想到一个介于外部 属性 名称和表示它的等效内部整数之间的字典。这将通过避免大量字符串处理开销来加速映射。
  • 中的您可以设想使用 unordered_map 来避免过多的字符串比较。