编写 GUI 程序对观察者模式的学习
复制本地路径 | 在线编辑
有一个项目,简短写了个 GUI 界面。但是后来,又增加一个需求:有的时候,我需要运行脚本去控制它。
其实就是一个相机出图的界面,上面可以进行一些设置。我是希望这个界面属于通用的,以后正常来说用这个 GUI 界面,偶尔有一些自动化任务,此时:应该直接启动脚本,脚本会解析到窗口,然后自定义各种操作。
错误做法
使用 pywinauto 去解析窗口,这个有几个缺点:
- pywinauto 有些元素无法解析出来,最经典的就是 TreeItem,也就是某个 checkbox 之类的元素同时也是 TreeItem,这个用了许多方法都无法解析出正确的元素,所以没办法用 checkbox 等特有的方法。
- pywinauto 的解析速度很慢,因为它是通过模拟鼠标和键盘来操作的,所以速度很慢。
- pywinauto 如果要用到鼠标和键盘,无法并行,而我的项目要求是要并行的。
即使忽略上面的缺点,这种做法还有一个最大的缺点:不直观,比如:
- 我想要保存图片怎么办,难道每次都是调用 GUI 上的按钮去保存吗,那多慢,保存一帧的时间好几帧就过去了
- 统计多帧的一些信息怎么办?GUI 上没有这样的信息呀
正确做法
脚本不应该调用 GUI 上的按钮,而是新建一个独立的 Controller,它是可以单独运行的,脚本和和 Controller 交互,GUI 也和 Controller 交互。
所以 GUI 一定要做到解耦,即:
- Controller 暴露各种方法接口,然后 GUI 或者外层脚本通过通信去下发任务给 Controller
- Controller 完成各种方法后,需要向各个层输出信号
- GUI 得到信号后才会修改 GUI 状态
而且脚本或者 GUI 刚启动的时候:
- 检查是否有启动的 Controller,如果有那么就去绑定,如果没有则自己开一个线程/进程去和它绑定
所以协议层可以通过网络通信来完成,因为这是跨进程的。
观察者模式
在上面的模型中,其实这就是设计模式一个很重要的 观察者模式 这个模型。如下图所示,GUI/CLI 不就是 Observer 吗,Subject 就是 Controller。

有的时候这个模式也叫做另一个名字,你绝对听过:发布-订阅。所以其实一目了然了,当然有的教条主义非要区分二者:发布-订阅中间有个专门负责转发的人:

Broker 就是专门的协议层,用来收发消息的。其实没有区别,上面 Controller 就是 Publisher+Broker 二者结合起来呗。如果是简单的项目,比如我们上面这个项目,直接 Controller 把收发消息的做出来就行了,没多几行代码。