写点什么

GUI 应用的若干问题和模式

  • 2012-05-23
  • 本文字数:3429 字

    阅读完需:约 11 分钟

我们所开发的应用程序大多都需要提供一个图形用户界面 (GUI)。关于 GUI 应用的架构设计, 已经有了很多模式, 比如 Martin Fowler 的 blog 中有一篇" GUI Architectures “, 里面介绍了 Form & Control、MVC、MVP、Passive View、Presentation Model、 Supervising Controller、Event Aggregator, Observer Synchronization 等多种模式。模式可以帮助我们建立优雅的架构, 但前提是弄清楚模式的应用场景。这些模式自然不是凭空产生的, 都是为了解决具体的问题. 模式在实现上的差别, 通常都体现了在约束间的不同取舍, 以及问题的差别. 弄清楚 GUI 应用面临的设计上的问题, 有助于我们正确的挑选设计方案. 下面我们来看一些 GUI 应用常见的设计问题。

第一个问题就是界面的变化和业务的变化频率不同, 通常是界面变化更频繁, 而我们希望一方的变化不至于影响另一方的逻辑. 对于这个问题, 一个自然的解决方案就是分离界面显示逻辑和后台业务逻辑. MVC 和 MVP 都涉及到了这一点, 它们的共同特点就是把 View 和应用程序的其它部分分开了. 这是一个关键的分离, 从此之后应用被分为两部分, 抛开它们彼此可以独立的变化不说. 最大的好处是这两部分的问题也可以分而治之。应用程序的其它部分有自己的问题和方案, 不在我们讨论范围内. 我们后面将聚焦在 View 和相关的显示逻辑方面的问题.

当然这种分离也不是没有代价的, 一个立即的问题就是 View 如何更新. MVC 和 MVP 把 View 分出来制造了这个问题, 它们也同时提供了手段解决这个问题。

  • MVP 中 Presenter 完成业务逻辑后可以拿到最新的 Model, 它可以操控视图, 根据最新的 Model 来设置视图的各种属性并刷新。
  • MVC 中 Controller 在完成业务逻辑操作后更新 Model, Model 变化时可以发出事件, View 订阅 Model 更新事件来更新自己。
  • MVC 有各种变体, 一种是 Controller 直接把 Model 推给 View, View 自己从 Model 中取出感兴趣的数据来刷新自己。

对视图更新的处理是 MVC 和 MVP 在实现上的主要区别: MVP 中 View 不需要知道 Model, Presenter 直接操作 View。MVC 中 View 知道 Model, 自己根据 Model 来更新自己的状态。

(图片来自: http://msdn.microsoft.com/en-us/library/ff647859.aspx )

跟 View 相关的另一个常见问题就是可测试性. 即使其它分出去的部分可以独立测试, 但剩下来的 View 依然 Hold 住了一部分显示相关的逻辑. 显示逻辑也是逻辑, 也需要测试, 而通常直接测试 GUI 界面是相对难以测试的. 现有直接测试 GUI 的测试工具都面临以下问题:

  • 测试耗时长, 因为要启动真实的应用
  • 测试比较脆弱, 无论是可靠性还是可维护性, 因为界面元素的变化很频繁, 而通过编程来控制界面和用户真实操作经常有细微的差别, 尤其是时序相关的问题

一个思路就是把显示逻辑从 View 中分离, 让 View 退化为简单的 GUI 控件的容器. MVP 做出了最初的努力, 而另外两个模式更加强调了这一点: Presentation Model Passive View

  • Passive View 针对可测试性的方案是把所有的显示逻辑都从 View 中移除, View 不再依赖任何 Model, 只是提供接口完全被动的由 Controller 或者 Presenter 来设置显示所需数据并刷新。
  • Presentation Model 则封装了 Domain Model 拥有的数据到 View 显示所需数据之间的映射。 View 不再需要与 Domain Model 打交道自己来把业务数据转换成显示需要的数据, View 只需从 Presentation Model 中取数据, 映射逻辑都在 Presentation Model 中。 而 View 所需数据和 Presentation Model 是简单的一一对应关系。

我们上面讨论的都是相对简单的 GUI, 比如我们其实假定了 View 和 Model 的一一对应, 甚至也假定了应用只有一个 View。 然而我们还有多视图的情况。 多视图带来了以下问题:

  • 当 Model 变化时如何保持多个视图间的一致性
  • 多个视图间的交互的可控性
  • 事件的循环触发问题

Martin Fowler blog 中描述的 Flow Synchronization Observer Synchronization 为当 Model 变化时刷新多个视图提供了两种方式, 分别应对不同的情况。

  • Flow Synchronization 在 Model 变化后的某些明确定义的时机明确的更新所有受影响的 View。 它的优点是显式, 直观, 可控, 缺点是很容易造成多个 View 之间彼此有依赖, 不易扩展, 因此它适用于视图较少的情况
  • Observer Synchronization 则是让多个 View 都订阅 Model 的更新事件。 这是 Observer 模式在同步方面的应用, 具有 Observer 松耦合的特点。 缺点也不意外, 它让用户交互的影响变的隐式了, 不易于理解应用整体行为和开发时调试等。

传统上还有一种用于解决交互的可控性并让 View 之间彼此解耦的模式, 就是 Mediator。 当我们在应用 Flow Synchronization 时, 如果把 View 之间的交互都抽取到一个中介者对象里面, 每个 View 都不知道其它 View, 只知道中介者对象, 当有事件发生时, 由中介者对象来更新 Model 和其它 View, 则我们可以获得相对清晰的交互和相对松散的耦合。 来看一下 << 设计模式 >> 里面对 Mediator 的描述:

意图:

  • 用一个中介对象来封装一系列对象交互。中介者使各对象不需要显式的相互引用,从而使其耦合松散,而且可以独立改变他们之间的交互

适用性:

  • 一组对象以定义良好但是复杂的方式进行通信。产生的相互依赖关系结构混乱且难以理解
  • 一组对象引用其它很多对象并且直接与这些对象通信,导致难以复用该对象

效果:

  • 它将各 Colleague 解耦。有利于各 Colleague 间的松耦合。可以独立的改变和复用各 Colleague 类和 Mediator 类
  • 简化了对象协议。用 Mediator 和各 Colleague 间的一对多的交互来代替多对多的交互
  • 对对象如何协作进行了抽象? 将中介作为一个独立的概念并将其封装在一个对象中,有助于弄清一个系统中的对象是如何交互的
  • 控制集中化。 中介者模式将交互的复杂性变为中介者的复杂性

多视图的另一个问题就是事件的循环触发问题。 场景如下:事件 A 发生 -> 事件 A 处理函数 -> 处理过程中触发了事件 B-> 事件 B 处理函数 -> 处理过程中又触发了事件 A->……一个简单的例子比如界面上有两个文本框, 要保证它们的和一直都是 100。 比如文本框 A 输入 30 的时候, 文本框 B 要显示 70。 文本框 B 输入 40 的时候, 文本框 A 要显示 60。 我们在处理第一个输入事件的时候需要设置第二个文本框的值, 而这个设值动作会触发第二个文本框的事件处理, 它也要设置第一个文本框的值……如此循环。

通常的处理方式有几种, 目的都相同:尽量减少不必要的事件发送

  • 状态真正改变时才发事件, 状态没有改变的话就不发事件。 上面例子中的 TextBox 控件。 如果连续用相同的参数调用其 SetText, 除了第一个调用可能会触发 TextChanged 事件外, 后续的操作都不会触发, 因其 Text 并未真的改变。 在我们的领域模型中触发事件可以遵循相同的 Pattern
  • 避免重入。 当事件处理函数开始事件处理的时候, 把自己置成一个不同的状态, 比如"处理中", 事件处理结束的时候再置回正常状态。 当在事件处理过程中触发新的事件又导致事件处理函数被调用, 可以检查自己是否在"处理中"的状态, 如果是的话忽略即可。
  • 根据事件的源头来决定是否处理。 这需要在事件的上下文中加入额外信息, 比如事件的发送者 sender。 微软的 CAB 框架允许指定事件的 Scope, 这样处理函数可以只处理自己感兴趣范围内的事件。
  • 严格遵循 CQRS 原则, 更新 Model 的函数和刷新视图的函数应该是两个函数, 分别是对用户输入事件的响应和 Model 改变事件的响应。 这样刷新视图不会再引入新的事件, 减少循环的几率。
  • 使用细粒度的事件。 粒度过粗会引发不必要的响应, 增加循环的可能

谈到事件的粒度, 过细的粒度会引起另外一个问题:注册事件处理函数太繁琐, 不易看清交互。 Event Aggregator 可以来解决这个问题。

模式

最后回过头来看一下已有的几个模式各自的重点 :

其中:

  • MVP 比 MVC 更强调显示逻辑跟视图的分离。
  • MVP, Presentation Model 和 Passive View 都强调视图跟显示逻辑的分离, 程度不同: MVP 引入这一分离, Passive View 分离的最彻底最可测, Presentation Model 介于两者之间。
  • Presentation Model 比 MVP 和 Passive View 更强调的是为显示逻辑创建单独的 Model, 而不是依赖于 Domain Model。

更全面的比较, 请参见老马的" GUI Architectures “, 及里面的链接。


感谢张凯峰对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。

2012-05-23 00:0010378

评论

发布
暂无评论
发现更多内容

微服务的10大问题

不在线第一只蜗牛

JavaScript 微服务

「宇树科技」启动IPO,29家产业链公司齐飞!

机器人头条

特斯拉 人形机器人 具身智能 宇树科技 智元机器人

嘉为蓝鲸 WeOps+Microsoft Teams:提升跨国运维信息传递精准度

嘉为蓝鲸

智能运维 #WeOps 一体化运维

CrossOver玩《幻兽帕鲁》进不去游戏、黑屏怎么办?

阿拉灯神丁

游戏卡顿 CrossOver Mac下载 如何在Mac上运行win游戏 幻兽帕鲁 雷神加速器

哈尔滨二级等保测评:关注重点与实施要点

等保测评

直播精彩回顾 | 拆解金融行业“隐形风险”,可观测性守护核心业务生命线

博睿数据

让复杂 AI 应用构建就像搭积木:Spring AI Alibaba Graph 使用指南与源码解读

阿里巴巴云原生

阿里云 微服务 云原生 Spring AI Alibaba

如何通过自动化工具发现10+SQL注入和30+XSS漏洞

qife122

网络安全 自动化工具

哈尔滨三级等保建设:从规划到落地的关键步骤

等保测评

CMeas效能洞察平台:10分钟,从数据到研发度量报表

嘉为蓝鲸

DevOps 智能运维 效能洞察

C#解析JSON数据全攻略

量贩潮汐·WholesaleTide

C# json

提示注入2.0:混合AI威胁下的新型网络安全挑战

qife122

网络安全 提示注入

内网IM:BeeWorks私有化部署的安全通讯解决方案

BeeWorks

即时通讯 IM 私有化部署

利用CSRF暴力破解用户ID实现批量删除用户攻击

qife122

CSRF WEB安全

OpsPilot 动态知识图谱上线:让企业知识具备“理解力”与“关联力”

嘉为蓝鲸

智能运维 #WeOps OpsPilot

KWDB多副本集群保姆级部署

KaiwuDB

Bonree ONE 发布直通车 | Bonree ONE多地多中心版本首发!全行业部署与应用深度解析

博睿数据

企业IM:BeeWorks私有化即时通讯助力高效协作

BeeWorks

即时通讯 IM 私有化部署

京东零售重磅开源 | OxyGent:像搭乐高一样组装AI团队,实现群体智能

京东零售技术

倒计时2天!合合信息WAIC黑科技剧透来袭!

合合技术团队

人工智能 算法 #大数据

Voice AI Agent 知识库:打造你自己的语音智能体!

RTE开发者社区

传奇IP续作:融合创新技术 数字娱乐产业迎来新发展机遇

江湖老铁

免费不限量,通义灵码已经全面支持 Qwen3-coder 模型,“效果很惊艳”

阿里云云效

开源 Qwen3-Coder 是顶级 AI 阳谋,阿里的野心藏不住了

程序员晚枫

开源 大模型

构建编程智能体一年实践的经验教训分享

Baihai IDP

程序员 AI AI Agent 编程智能体

硬核来袭!「AI 进化论:智算时代 OS 的破局之路」首期直播上线

OpenAnolis小助手

centos AI 操作系统 龙蜥社区 智算时代

再添荣誉!嘉为蓝鲸斩获可信云技术典型实践大奖,彰显智能运维实力

嘉为蓝鲸

AIOPS 智能运维 cmp 可信云大会

嘉为蓝鲸CTeam敏捷协同平台:一站式实现Jira迁移与研发管理升级

嘉为蓝鲸

DevOps 智能运维 敏捷协同平台

Seed 端到端同声传译大模型:3s 延迟,实时声音复刻;昆仑万维 Mureka TTS 更新,支持音色设计丨日报

RTE开发者社区

BEVDet 算法详细解读-全网最全攻略

十三Tech

Mac mini玩游戏怎么样?怎么提高Mac mini玩游戏的流畅度?

阿拉灯神丁

CrossOver Mac下载 如何在Mac上运行win游戏 苹果电脑必备软件 Mac游戏推荐 虚拟机安装

GUI应用的若干问题和模式_ThoughtWorks_李光磊_InfoQ精选文章