Welcome 微信登录

首页 / 网页编程 / ASP.NET / RichClient/RIA原则与实践(下)

RichClient/RIA原则与实践(下)2011-09-21 infoq 陈金洲3 事件管理

事件管理应当是整个RichClient/RIA开发中的最难以把握的部分。这部分控制的好,你的程序用起来 将如行云流水,用户的思维不会被打断。任何一 个做RichClient开发的程序员,可以对其他方面毫无所 知,但这部分应当非常熟悉。事件是RichClient的核心,是“一切皆异步”的终极实现。前面所说的例子 ,实际上可以被抽象为事件,例如第一个,获取股票数据,从事件的观点看,应该是:

开始获取股票数据

正在获取股票数据

获取数据完成

获取数据失败

看起来相当复杂。然而这样去考虑的时候,你可以将执行计算与界面展现清晰的分开。界面只需要响 应事件,运算可以在另外的地方 悄悄的进行,并当任务完成或者失败的是时候报告相应的事件。从经验 看来,往往同样的数据会在不同的地方进行不同的展示,例如skype在通话的时候这个人 的头像会显示为 占线,而具体的通话窗口中又是另外不同的展现;MSN的个人签名在好友列表窗口中显示为一个点击可以 编辑控件,而同时在聊天窗口显示为一个 不能点击只能看的标签。这是RichClient的特性,你永远不知 道同一份数据会以什么形式来展现,更要命的是,当数据在一个地方更新的时候,其他所有 能展现的地 方都需要同时做相应的更新。如果我们仍然以第一部分的例子,简单采用runInAnoterThread是完全不能 解决这个问题的。

我们曾经犯过一些很严重的错误,导致最终即便重构都积重难返。无视事件的抽象带来的影响是架构 级别的,小修小补将无济于事。

事件的实现方式可以有很多种。对于没有事件支持的语言,接口或者干脆某一个约束的方法就可以。 有事件支持的语言能够享受到好处,但仍然是语法级别的,根本 是一样的。观察者模式在这里很好用。 仍然以股票为例,被观察的对象就是获取股票数据对象StockDataRetriver,观察的就是StockWindow:

StockDataRetriver {
observers: []

retrieve() {
try {
theData = ...// 从远程获取数据
observers.each {|o| o.stockDataReady(theData)} // 触发数据获取成功事件
} catch {
observers.each { |o| o.stockDataFailed() } // 触发事件获取失败事件
}
}
}


StockDataRetriver.observers.add(StockWindow) // 将StockWindow加入到观察者队列


StockWindow {
stockDataReady(theData) {
showDataInUIThread(); // 在UI线程显示数据
}
stockDataFailed() {
showErrorInUIThread(); // 在UI线程显示错误
}
}