使用工厂模式实例化所有小部件是明智的吗?



我正在考虑使用工厂模式在我的一个小GUI工具包中实现样式和渲染,然后这个疯狂的想法让我震惊。为什么不对所有小部件使用工厂模式呢?

现在我在想这样的风格:

Widget label = Widget::create("label", "Hello, World");
Widget byebtn = Widget::create("button", "Good Bye!");
byebtn.onEvent("click", &goodByeHandler);

新的小部件类型将注册一个函数,如Widget::register(std::string ref, factfunc(*fact))

你认为这种方法的优缺点是什么?

我敢打赌,使用std::map<std::string>几乎没有性能问题,因为它只在设置时使用。

是的,请原谅我被JavaScript和c++中任何可能的语法错误所破坏,因为我已经有一段时间没有使用这种语言了。


利弊总结

优点

  • 从文件中动态加载新的小部件是很容易的
  • 部件可以很容易地在运行时被替换(它也可以帮助单元测试)
  • 对动态人群的吸引力

缺点(和可能的解决方案)

    不进行编译时检查(可以编写自己的构建时检查)。JS/Python/命名它,也不进行编译时检查;我相信开发者没有它也能做得很好)
  • 可能性能较差(不需要一直创建小部件)。字符串映射不会一直使用,而是在创建小部件和注册事件处理程序时使用
  • Up/Downcasting hell(在需要的地方提供通常的类实例化)
  • 可能使配置小部件变得更加困难(使小部件具有相同的选项)

我的GUI Toolkit还处于早期阶段,它在规划方面缺乏很多东西。由于我不习惯制作GUI框架,所以可能有很多问题/设计决定我甚至还没有考虑过。

现在我看不出widget在它们的方法集上有什么不同,但这可能只是因为我还没有在脑海中完成更高级的widget。

谢谢大家的意见!

优点

  • 从文件或其他外部源中读取小部件并按其名称创建它们是很容易的。

  • 很容易将不正确的类型名称传递给Widget::create,并且只在运行时得到错误。
  • 你将无法访问特定于小部件的API而不进行降级——也就是说,又多了一个运行时错误的来源。
  • 找到创建特定类型小部件的所有位置可能不那么容易。

为什么不同时使用常规构造函数和工厂来创建小部件呢?

我认为这不是很直观。我宁愿允许直接访问这些类。这里的问题是,你为什么要这样做。有技术上的原因吗?在包含小部件的"真实类"之上是否有更高的抽象层?例如,您有用于外部API的纯虚拟类,然后是实现类?但是,在不知道您的库是如何设置的情况下,很难说这是否有任何好处,但我本人并不是工厂的忠实粉丝,除非您真的需要它们。如果你有这个更高的抽象层,并且想要那个工厂,那就看看光吧。它为API使用纯虚拟类,然后使用"实现类"。工厂根据选择的渲染器(directx, opengl, software)选择正确的实现。但是它们不通过字符串来标识需要的类。这是我在c++中不会做的事情。我的两分钱。

我建议不要使用string作为键,并为每个子类型推广一个真正的方法。

class Factory
{
public:
  std::unique_ptr<Label> createLabel(std::string const& v);
  std::unique_ptr<Button> createButton(std::string const& v, Action const* a);
};

这有几个优点:

  • 编译器检查,你可以拼写错误的字符串,但你不能得到一个运行的程序与拼写错误的方法
  • 更精确的返回类型,因此,不需要向上转换(和它的所有麻烦)
  • 更精确的参数,因为不是所有元素都需要相同的参数集

通常,这样做是为了允许自定义。如果Factory是一个抽象接口,那么你可以有几个实现(Windows, GTK, Mac)在底层不同地创建它们。

然后,你可以一次切换整个工厂,而不是为每个类型设置一个创建者函数。

注意:性能方面,虚拟函数比通过字符串键

查找映射要快得多

最新更新