我有一个 Node 类模板,它采用数据类型作为模板参数:
template <class T_Data>
class Node
{
};
Node 类能够在某些事件上通知用户/监听器。此功能是使用 libsigc++
信号实现的,但在发出信号之前,Node 会通知一个处理程序对象,该对象会进行一些处理并决定是否发出信号。这个处理程序对象存在是因为在某些情况下我希望节点对象处理它们的 oen 事件,阻塞信号。
常见的解决方案是为 Node 提供任何人都可以在派生类中覆盖的虚拟方法,但是由于 Node 使用对自身的引用并创建自己类型的对象,因此拥有一个 HandlerBase 类并让人们派生处理程序会更容易。
一切都很顺利,直到我编写了一个处理程序类并且我想让我的节点使用它。但是为了启用新的处理程序,我需要调用静态 Node 方法 Node::set_event_handler()
。这意味着我必须记得在某个地方调用它。如果有人想使用我的处理程序,他们必须记住在 main() 或某个主类的构造函数中设置处理程序,也许是他们在 GUI 应用程序中的 Window 类。
template <class T_Data>
class Node
{
public:
static void set_event_handler (std::unique_ptr <HandlerBase> new_handler);
private:
static std::unique_ptr <HandlerBase> event_handler;
};
所以我想到了两种可能的解决方案:
- 将对
set_handler()
的调用放在我的一些主类中 - 为 Node 类添加一个 T_Handler 模板参数
目前,静态处理程序字段设置为新的 HanderBase,它会忽略所有信号。如果我使用模板参数,将有可能具有相同的数据类型和不同的处理程序,并且静态字段将在初始化时设置,因此不需要额外的工作。
问题是,T_Handler 是否不仅给 Node 添加了“困惑”,在为处理程序类型添加模板参数的意义上使其变得不那么“干净”,而许多 Node 用户甚至不需要。
实际上,我也可以给 T_Handler 一个默认值,这样用户就可以忘记它,因为他们不需要它,但我仍然很好奇哪种设计可能更好。
最佳答案
当然,它会增加困惑并使其不那么干净。然而,这真的是一个大问题吗?我想这取决于您的观点。
如果您查看标准库中的许多模板,您会看到大多数用户不需要的模板参数。默认值以及 typedef
用于隐藏这种困惑。例如,参见 std::basic_string ,其中:
- 大多数用户不关心
traits
或Alloc
,所以这些参数有默认值 charT
的一个流行值就是char
,因此 std::string类型定义为速记。
请注意,这种困惑只是隐藏的。如果你需要调试你的代码并且你正在调试器中查看你的变量类型,它就会出来咬你。 ;)
关于C++ 类设计建议,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16363762/