- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
假设我有一个名为 Component 的抽象基类,它是 GUI 组件层次结构的根。在这种情况下,我们可能有两个子类,Button 和 Label,它们也是抽象类,并且作为它们各自的具体类层次结构的根存在。
继承自 Button 的具体类可能包括 RoundButton 和 SquareButton。
继承自 Label 的具体类可能包括 TextLabel 和 PictureLabel。
最后,假设有一个包含组件对象集合的聚合容器类。
问题是我有指向组件对象的指针,但我需要将它们标识为按钮或标签。例如,如果我想指定所有 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 成员。
解决这个问题的好方法是什么?就我而言,性能是关键,虽然类似于枚举解决方案的东西看起来很简单,但我想知道我是否忽略了更好的方法。
--- 编辑 ---
我意识到我可能应该指出,在实际系统中,等效容器只能存储每个系列中的 1 个组件。因此,Components实际上存储在一个映射中,例如:
std:map<COMPONENT_FAMILY, Component*>
应用到我这里的简单示例,这意味着一个容器只能包含 1 个按钮、1 个标签等。
这使得检查特定类型的组件(日志时间)是否存在变得非常容易。因此,这个问题更多的是关于如何表示COMPONENT_FAMILY,以及在将组件添加到 map 时如何确定组件的类型。
换句话说,组件的唯一目的是被识别为添加到容器中的特定功能,所有组件一起定义容器的特定行为。
所以,我不需要知道组件的类型,这已经暗示了。我特意向 Container 询问特定类型的 Component。我需要的是一种让组件传达其类型的方式,以便它可以首先进行映射。
最佳答案
I need to identify them as being either Buttons or Labels.
那是你的问题。这种假设虽然很常见,但通常是错误的。
您可以通过在构造时为控件分配 UI 策略来绕过了解其具体类型的“要求”。在绘制时(或任何时候)在基类中检索该 UI 策略的字体属性:
class IVisualStrategy
{
...
virtual const Font& GetFont() const = 0;
...
};
class HeavyVisuals : public IVisualStrategy
{
Font font_;
...
HeavyVisuals() : font_(15, Bold) {}
virtual const Font& GetFont() const { return font_; }
...
};
class LightVisuals : public IVisualStrategy
{
Font font_;
...
LightVisuals() : font_(12, Regular) {}
virtual const Font& GetFont() const { return font_; }
...
};
从基地检索:
class Control
{
...
private:
void OnPaintOrSomething()
{
DrawTextWithFont(GetVisualStrategy().GetFont());
}
virtual const IVisualStrategy& GetVisualStrategy() const = 0;
};
class Button : public Control
{
HeavyVisualStrategy visualStrategy_;
...
private:
virtual const IVisualStrategy& GetVisualStrategy() const
{
return visualStrategy_;
}
}
class Label : public Control
{
LightVisualStrategy visualStrategy_;
...
private:
virtual const IVisualStrategy& GetVisualStrategy() const
{
return visualStrategy_;
}
}
更灵活的设计是在具体控件类中保留指向 IVisualStrategy 的共享指针,并通过构造函数注入(inject)它,而不是将它们硬设置为 Heavy 或 Light。
此外,为了在此设计中的对象之间共享字体,Flyweight pattern可以应用。
关于C++ - 在不引入紧密耦合的情况下识别多态类族,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6265791/
在C中,protocol family被提及为第一个参数。 例如: ipv4 的套接字(AF_INET,,) socket(AF_PACKET,,) 用于数据包嗅探 Python 支持三个地址族:AF
根据 vfork() 手册页,如果 vfork() 在调用 _exit 或 exec 之前修改除 pid_t 之外的任何数据,则行为未定义系统调用系列。 由此我了解到,如果vfork()创建的子进程调
我是一名优秀的程序员,十分优秀!