多态性或性质词典

Polymorphism or dictionary of properties?

本文关键字:多态性      更新时间:2023-10-16

我需要解析XML并在与XML元素相对应的C 中创建对象,还将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 ();

对于 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.
};

所有派生类都有arguments映射;为了获得属性值,我们扫描字典以按名称查找属性,然后读取其值,例如GetArgumentOrEmpty(TAG_XML_ATTRIBUTE_WEIGHT)。如今,CPU很快,因此搜索字典不会明显影响性能。元素/属性的名称空间从结构化(作为类成员)到平面(作为#Define列表),但它们都将在一个地方。代码更加抽象;尽管由于额外的间接方式,对象处理代码变得更加复杂,但如果属性名称更改,则不需要更改。例如如果XML中的passengers更改为people,则#Define看起来有些尴尬,但是使用它的代码不必更改:

#define TAG_XML_ATTRIBUTE_PASSENGERS        "people"

基于字典的属性访问方法是否有足够的好处将其用于生产代码而不是使用常规类属性?如果是这样,是仅针对此特定的XML放置案例还是用字典搜索替换多态性,用字符串名称代替类属性是一个更好的主意?

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

  • 很容易在类/对象中添加新的新属性。
  • 对象加载/保存/创建代码将非常通用。
  • 可以使属于类完全配置的类的属性
  • 实际上更难维护和丰富。

也有一些不便:

  • 特定于类的处理代码将被getters混乱
  • 此代码将在很大程度上取决于属性命名,这使得可配置性不易。
  • 由于未注意的错字,很容易将错误进入系统:编译器不会发现这些不一致之处,因为它只是刻板数据。

因此,您必须做出一个艰难的选择。我的建议是:

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

如果您去了地图,则有几个想法:

  • 您可以想到外部属性名称与代表它的内部整数之间的字典。这将通过避免大量的字符串处理开销来加速地图。
  • 您可以使用unordered_map设想,以避免过多的字符串比较。