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線程顯示錯誤
}
}