【发布时间】:2014-09-17 21:14:01
【问题描述】:
是否有一种惯用的 C++ 方法将属性与一组固定的类实例动态关联?
假设我们有一个 Element 类。每个元素总是具有某些属性,这些属性包含在成员变量中。
struct Element {
unsigned atomic_protons;
float mass;
};
我们可能会将其他属性与每个 Element 相关联,但并非每个使用 Element 类的程序都会对相同的属性感兴趣。也许有时我们对味道感兴趣,有时我们对颜色感兴趣,代表这些属性的变量可能初始化起来很昂贵。也许直到运行时我们才知道我们需要什么属性。
我想到的解决方案是一组并行数组。一个数组包含实例本身,并且该数组的索引隐含地将每个实例与一系列“并行”数组中的项目相关联。
// fixed set of Element instances
std::vector<Element> elements;
// dynamic properties
std::vector<Flavor> element_flavors;
std::vector<Color> element_colors;
每个属性向量都是根据需要创建的。
这个解决方案没问题,但一点也不像惯用的 C++。除了美观之外,这种安排还使得从给定的 Element 实例中查找属性变得很尴尬。我们需要在每个 Element 实例中插入一个数组索引。另外,每个向量中的大小信息都是多余的。
如果我们对给定属性的所有值感兴趣,那么它的优点是数据会被适当地排列。但是,通常我们想朝相反的方向前进。
以某种方式修改 Element 类的解决方案很好,只要每次添加新属性时都不需要修改该类。还假设存在所有程序共享的用于处理 Element 类的方法,我们不希望这些方法中断。
【问题讨论】:
-
如果初始化它们的开销是主要问题,延迟初始化可能是一种选择,即携带指向成员的空指针,但只有在实际尝试访问它们时才实际创建它们。
-
如何使用这些属性?在理想的 OO 设计中,属性将是私有的,并且仅由 Element 类上的函数使用。这让生活更轻松,因为您可以在 Element 中拥有虚函数,然后在派生类中专门化行为(并使用其他属性)。如果派生类开始出现爆炸式增长,请考虑使用装饰器模式。
-
@ChrisDrew 类似遍历元素实例的集合,并根据每个实例先前“标记”的属性来做一些事情。因此,我们想要一种有效的方法来从 Element 映射到感兴趣的属性,而无需为不必要的属性付费。不知道有没有合理的方式在运行时挑选装饰器?
-
@Praxeolitic,您可以轻松地“标记”一个元素,方法是用在运行时包装元素的装饰器替换它。 IElement 说,装饰器和元素将从同一个接口继承。然后,您可以拥有一个 IElement 集合,并将标记和未标记的元素视为相同。问题是 IElement 上可用的操作是固定的。不过,您可以根据标记方式更改这些操作的行为。
标签: c++ oop design-patterns