drb*_*rby 4 c++ user-interface signals-slots
我有一个程序(除此之外)有一个命令行界面,让用户输入字符串,然后通过网络发送.问题是我不确定如何将在GUI内部生成的事件连接到网络接口.假设我的GUI类层次结构如下所示:
GUI - > MainWindow - > CommandLineInterface - > EntryField
每个GUI对象都包含一些其他GUI对象,一切都是私有的.现在,entryField对象生成一个已输入消息的事件/信号.目前我正在将信号传递给类层次结构,因此CLI类看起来像这样:
public:
sig::csignal<void, string> msgEntered;
Run Code Online (Sandbox Code Playgroud)
而在c'tor:
entryField.msgEntered.connect(sigc::mem_fun(this, &CLI::passUp));
Run Code Online (Sandbox Code Playgroud)
passUp函数只是为拥有类(MainWindow)再次发出信号才能连接,直到我最终可以在主循环中执行此操作:
gui.msgEntered.connect(sigc::mem_fun(networkInterface, &NetworkInterface::sendMSG));
Run Code Online (Sandbox Code Playgroud)
现在这似乎是一个非常糟糕的解决方案.每次我向GUI添加内容时,我都必须通过类层次结构将其连接起来.我确实看到了几种方法.我可以将所有对象公开,这将允许我在主循环中执行此操作:
gui.mainWindow.cli.entryField.msgEntered.connect(sigc::mem_fun(networkInterface, &NetworkInterface::sendMSG));
Run Code Online (Sandbox Code Playgroud)
但这违背了封装的想法.我还可以在整个GUI上传递对网络接口的引用,但我希望尽可能保持GUI代码的分离.
感觉我在这里缺少必要的东西.有干净的方法吗?
注意:我正在使用GTK +/gtkmm/LibSigC++,但我没有标记它,因为我和Qt有同样的问题.这是一个普遍的问题.
根本问题在于您将GUI视为单片应用程序,只有gui通过比平时更大的线路连接到逻辑的其余部分.
您需要重新考虑GUI与后端服务器交互的方式.通常,这意味着您的GUI将成为一个独立的应用程序,它几乎不执行任何操作,并且在没有GUI内部(即您的信号和事件)与服务器处理逻辑之间的任何直接耦合的情况下与服务器进行通信.也就是说,当您单击一个按钮时,您可能希望它执行某些操作,在这种情况下您需要调用服务器,但几乎所有其他事件只需要更改GUI中的状态并且不对服务器执行任何操作 - 直到你准备好了,或者用户想要一些回复,或者你有足够的空闲时间在后台拨打电话.
诀窍是完全独立于GUI定义服务器的接口.您应该可以在以后更改GUI而无需修改服务器.
这意味着您将无法自动发送事件,您需要手动连接它们.
如果没有一些全球发布/订阅中心,您将无法避免在层次结构中向上或向下传递某些内容。即使您将侦听器抽象为通用接口或控制器,您仍然必须以某种方式将控制器附加到 UI 事件。
使用发布/订阅集线器,您可以添加另一层间接层,但仍然存在重复 - EntryField 仍然显示“发布消息就绪事件”,而侦听器/控制器/网络接口显示“侦听消息就绪事件”,因此有一个常见的双方都需要了解的事件 ID,如果您不打算在两个地方对其进行硬编码,则需要将其传递到两个文件中(尽管作为全局文件,它不会作为参数传递;其本身并不是“没有任何很大的优势)。
我已经使用了所有四种方法 - 直接耦合、控制器、监听器和发布-订阅 - 在每个后继者中,你稍微放松了耦合,但你永远无法摆脱一些重复,即使它只是 id已发布的事件。
这实际上归结为差异。如果您发现需要切换到接口的不同实现,那么将具体接口抽象为控制器是值得的。如果您发现需要有其他逻辑来观察状态,请将其更改为观察者。如果您需要在进程之间解耦,或者想要插入更通用的体系结构,发布/订阅可以工作,但它引入了一种全局状态形式,并且不适合编译时检查。
但如果您不需要独立改变系统的各个部分,那么可能就不值得担心。
| 归档时间: |
|
| 查看次数: |
3484 次 |
| 最近记录: |