假设我有一个名为 Component 的抽象基类,它是 GUI 组件层次结构的根。在这种情况下,我们可能有两个子类,Button 和 Label,它们也是抽象类,并且作为它们各自的具体类层次结构的根而存在。
从 Button 继承的具体类可能包括 RoundButton 和 SquareButton。
从 Label 继承的具体类可能包括 TextLabel 和 PictureLabel。
最后,假设有一个聚合 Container 类,其中包含 Component 对象的集合。
问题是我有指向组件对象的指针,但我需要将它们标识为按钮或标签。例如,如果我想指定所有 Button 的内部文本应该有一个更大的字体,我可以遍历 Container 中的所有 Component 对象,并以某种方式确定哪些是按钮,并调用一些特定于按钮的方法。
这些组件“家族”标识自己的一种方法是使用字符串。
class Component {
public:
virtual char const * const getFamilyID() const = 0;
};
// In Button.h
char const * const COMPONENT_BUTTON = "button";
class Button : public Component {
public:
virtual char const * const getFamilyID() const { return COMPONENT_BUTTON; };
};
// Code sample
if (strcmp(component->getFamilyID(),COMPONENT_BUTTON) == 0)
// It's a button!
这是松耦合的,因为 Component 将定义这些族的任务留给了它的子级;它不需要知道存在哪些家庭。客户需要了解不同的组件系列,但如果它试图针对某个特定的组件系列进行某些操作,那么这是无法避免的。
但是,假设我们有非常高的性能要求并且我们希望避免比较字符串。避免使这个函数成为虚拟函数也很好,这样我们就可以内联它。此外,如果 Component 的每个子类都需要声明一个全局常量,那么以某种方式修改 Component 类以使其成为要求或使其成为不必要可能会很好。
解决此问题的一种方法是在 Component.h 中定义一个枚举器
enum COMPONENT_FAMILY {
COMPONENT_BUTTON = 0,
COMPONENT_LABEL,
// etc...
};
在这种情况下 getFamilyID() 可以只返回一个 COMPONENT_FAMILY 枚举,我们基本上可以只比较整数。不幸的是,这意味着任何新的组件系列都必须在这个枚举中“注册”,这很容易,但对于其他程序员来说并不完全直观。此外,该方法仍然必须是虚拟的,除非我们创建一个非静态 COMPONENT_FAMILY 成员,我们知道该成员将具有极低的基数(不理想)。
解决这个问题的好方法是什么?就我而言,性能是关键,虽然类似于 enum 解决方案的东西似乎很容易,但我想知道我是否忽略了更好的方法。
--- 编辑 ---
我意识到我应该指出,在实际系统中,Container 等效项只能存储每个系列的 1 个组件。因此,组件实际上存储在一个映射中,例如:
std:map<COMPONENT_FAMILY, Component*>
应用于我这里的简单示例,这意味着容器只能包含 1 个按钮、1 个标签等。
这使得检查特定类型的组件(日志时间)是否存在变得非常容易。因此,这个问题更多是关于如何表示 COMPONENT_FAMILY,以及在我将其添加到地图时如何确定 Component 的类型。
换句话说,组件的唯一目的是被识别为添加到容器的特定功能,所有组件一起定义容器的特定行为。
所以,我不需要知道组件的类型,这已经隐含了。我专门向容器询问特定类型的组件。我需要的是一种让组件传达其类型的方法,以便可以首先对其进行映射。