<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    憨厚生

    ----Java's Slave----
    ***Java's Host***

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      165 隨筆 :: 17 文章 :: 90 評論 :: 0 Trackbacks
    轉(zhuǎn) http://www.infoq.com/cn/articles/thoughtworks-practice-partiii

    RichClient/RIA原則與實踐(上)

    作者 陳金洲 發(fā)布于 2009年3月10日 上午4時8分

    社區(qū)
    .NET,
    Agile,
    Java
    主題
    RIA,
    富客戶端/桌面
    標(biāo)簽
    原則

    Web領(lǐng)域的經(jīng)驗在過去十多年的不斷的使用和錘煉中,整個 開發(fā)領(lǐng)域的技術(shù)、理念、缺陷已經(jīng)趨于成熟。JavaEE Stack, .NET Stack, Ruby On Rails等框架代表了目前這個技術(shù)領(lǐng)域的所有經(jīng)驗積累。這樣我們在開始一個新的項目的時候,只需要選擇對應(yīng)語言的最佳實踐,基本上不會犯大的錯誤。例 如,如果使用Java開發(fā)一個新的Web應(yīng)用,那么基本上Spring/Guice+Hibernate/iBatis/+Struts /SpringMVC這種架構(gòu)是不會產(chǎn)生重大的架構(gòu)問題的;如果使用RoR那么你已經(jīng)在使用最佳實踐了;系統(tǒng)的分層:領(lǐng)域?qū)?,?shù)據(jù)庫層,服務(wù)層,表現(xiàn)層等 等;為了保證系統(tǒng)的可擴(kuò)展性,服務(wù)器端應(yīng)當(dāng)是無狀態(tài)架構(gòu),等等。總而言之,web開發(fā)領(lǐng)域,它豐富的積累使得開發(fā)者逐漸將更多的精力投入到應(yīng)用本身。

    來看富客戶端,或者富互聯(lián)網(wǎng)應(yīng)用。在我看來,今天的RichClient與RIA已經(jīng)沒有分別:只要代表著豐富界面元素和豐富用戶體驗,需要與服務(wù)器進(jìn)行 交互的應(yīng)用都可以稱為RichClient或者RIA,雖然感覺上RichClient更“企業(yè)化”一些(服務(wù)器往往在企業(yè)內(nèi)部),RIA更“個人化”一 些(服務(wù)器往往處于公網(wǎng))。從最小的層面來說,我現(xiàn)在正在使用的離線模式的GoogleDoc就是一個RichClient應(yīng)用──雖然它沒有那么 Rich,采用和microsoft office一樣土的界面; 我現(xiàn)在正在聽音樂的Last.fm客戶端顯然是一個非常典型的RIA──它所有的個人喜好信息、音樂全都來自遠(yuǎn)在美國的服務(wù)器。本地的這個界面,只是提供 收集個人和音樂信息,以及控制音樂的播放和停止;目前擁有1150萬玩家的魔獸世界,則是一個掙錢最多的,最“富”的客戶端,10多G的客戶端包含了電影 品質(zhì)的廣闊場景,華麗的魔法效果和極其復(fù)雜的人機(jī)交互。

    如今的用戶需求已經(jīng)達(dá)到了一個新的高度,那些灰色的,方方正正的界面已經(jīng)逐漸不能夠滿足客戶的需求。從我們工作的客戶看來,他們除了對“完成功能”有著基 本的期待外,對于將應(yīng)用做得“酷”,也抱有極大的熱情。我工作的上一個項目是一個CRM系統(tǒng),它是基于.NET Framework 3.5的一個RichClient應(yīng)用。它的主窗口是一個帶著紅色漸變背景的無邊框窗口,還有請專業(yè)美工制作的圖標(biāo),點擊某一個菜單還有華麗的二級菜單滑 動效果。我們在這個項目中獲得了很多,有些值得借鑒,有些仍然值得反思。我仍然記得我們在項目的不同階段,做一個技術(shù)決定是如此的彷徨和忐忑:因為在當(dāng)時 的RichClient企業(yè)開發(fā)領(lǐng)域,幾乎沒有任何豐富的經(jīng)驗可以借鑒,我們重新發(fā)明了一些輪子,然后又推翻它;我們偏離了UI框架給我們提供的各種便利 而自己實現(xiàn)種種基礎(chǔ)特性,只是因為他們偏離了我們所倡導(dǎo)的測試性的原則。在寫下本文的時候,我嘗試搜索了一下,仍然沒有比較深入的實踐性文章來介紹企業(yè)環(huán) 境下RichClient開發(fā)。大多數(shù)的書,如Swing、JavaFX、.NET WPF開發(fā)等等,偏向于小規(guī)模特性介紹,而在大規(guī)模的企業(yè)應(yīng)用中,這些小的技巧對于架構(gòu)決策往往幫助很小。

    我的工作經(jīng)歷應(yīng)當(dāng)是和大多數(shù)開始進(jìn)行RichClient開發(fā)的開發(fā)者類似:有著豐富的Web開發(fā)的經(jīng)驗之后開始進(jìn)行RichClient開發(fā)。加入 ThoughtWorks之后參加了多個不同的RichClient項目的開發(fā)工作,使用/嘗試過的語言包括Java Swing, Flex/Adobe Air, .NET WinForm/.NET WPF. 對于不同平臺之間的種種有些體會。在這里我將這些實踐和原則總結(jié)如下。例子很可能過時,畢竟華麗的界面框架層出不窮,但原則應(yīng)當(dāng)通用的。使用和遵循這些原 則將會幫助你少犯錯誤──至少比我們過去犯的錯誤要少。如果你擁有一定的web開發(fā)經(jīng)驗,那么這篇文章你讀起來會很親切。

    這些原則/實踐往往不是孤立的,我嘗試將他們之間用圖的方式關(guān)聯(lián)起來,幫助你在使用的過程中進(jìn)行選擇。例如,你遵循了“一切皆異步”的原則,那么很可能你 需要進(jìn)行“線程管理”和“事件管理”;如果你需要引入“緩存與本地存儲”,那么“數(shù)據(jù)交互模式”你也需要進(jìn)行考慮。希望這張圖能夠幫助讀者理解不同原則之間的聯(lián)系。

    下面列出的這些原則或者實踐沒有嚴(yán)格意義上的區(qū)分。按照上面的圖,我推薦是,一旦你考慮到了某一個實踐,那么與它直接關(guān)聯(lián)的實踐你最好也要實現(xiàn)。它會使得你的架構(gòu)更全面,經(jīng)得起用戶功能的需求和交互的需求。

    為了讓這些實踐更加通用,我采用偽代碼書寫。相信讀者能夠轉(zhuǎn)化成相應(yīng)的語言──Java, C#, ActionScript或者其他。這些實踐并非與某一種語言相關(guān)。在某些特定的例子中,我會采用特定語言,但大多數(shù)都是偽代碼描述的。

    1 一切皆異步

    所有耗時的操作都應(yīng)當(dāng)異步進(jìn)行。這是第一條、也是最重要的原則,違背了這條原則將會導(dǎo)致你的應(yīng)用完全不可用。

    考慮這樣的一個功能:點擊一個"更新股票信息"按鈕,系統(tǒng)會從股票市場(第三方應(yīng)用)獲得最新的股票信息,并將信息更新到主界面。絲毫不考慮用戶體驗的寫法:

    void updateStockDataButton_clicked() {
        stockData = stockDataService.getLatest(); // 從遠(yuǎn)程獲取股票信息
        updateUI(stockData); // 這個方法會更新界面
    }

    那么,當(dāng)用戶點擊updateStockDataButton的時候,會有什么反應(yīng)?難說。如果是一個無限帶寬、無限計算資源的世界,這段代碼直觀又易 懂,而且工作的非常好:它會從第三方股票系統(tǒng)讀到股票數(shù)據(jù),并且更新到界面上??上Р皇恰_@段代碼在現(xiàn)實世界工作的時候,當(dāng)用戶點擊這個按鈕,整個界面會 凍結(jié)──知道那種感覺嗎?就是點完這個按鈕,界面不動了;如果你在使用Windows, 然后嘗試拽住窗口到處移動,你會發(fā)現(xiàn)這個窗口經(jīng)過的地方都是白的。你的客戶不會理解你的程序?qū)嶋H上在很努力的從股票市場獲得數(shù)據(jù),他們只會很憤怒的說,這 個東西把我的機(jī)器弄死了!他們的思路被打斷了。于是他們不再使用你的程序,你們的合作沒了。你沒錢了。你的狗也跑了。

    出現(xiàn)界面凍結(jié)的原因是,耗時操作阻塞了UI線程。UI線程一般負(fù)責(zé)著渲染界面,響應(yīng)用戶交互,如果這個線程被阻塞,它將無法響應(yīng)所有的用戶交互請求,甚至 包括拖拽窗口這樣簡單的操作。所有的界面框架,無論是Java/.NET/ActionScript/JavaScript, 都只有一個UI線程,這個估計永遠(yuǎn)都不會變。

    用戶看到的應(yīng)用通常與程序員大相徑庭。用戶對應(yīng)用的期待級別分別是:能用、可用、好用、好看。而我觀察到的大多數(shù)程序員停留在第一階段:能用。“一切皆異步”這個原則說來簡單,做起來也不會很難。把上面的代碼稍作改動,如下:

    void updateStockDataButton_clicked() {
        runInAnotherThread( function () {
            stockData = stockDataService.getLatest(); // 從遠(yuǎn)程獲取股票信息
            updateUI(stockData); // 這個方法在UI線程更新界面
        }
    }

    注意加粗部分。runInAnotherThread是跟語言平臺特定的。對于.net C#,可以是一個Dispatcher+delegate或者ThreadPool.QueueUserWorkItem;對于Java,可以干脆是一個Runable。對于AJAX, 可以是XMLHttpRequest或者把這個計算扔到一個IFrame中;對于ActionScript, 似乎沒有什么好的方法,把獲取數(shù)據(jù)的部分交給XML.load然后通過事件回調(diào)的方式來進(jìn)行界面刷新吧。

    耗時操作一般兩種來源產(chǎn)生:網(wǎng)絡(luò)帶來的延遲以及大規(guī)模運算。兩者對應(yīng)的異步實現(xiàn)方式有所不同。前者往往可以通過特定語言、平臺的獲取數(shù)據(jù)的方式來進(jìn)行異步,特別是缺乏多線程特性的動態(tài)語言。例如典型的AJAX方式:

    xhr = new XmlHttpRequest()
    xhr.send("POST", '/stockData/MSFT', function() {
        doSomethingWith(xhr.responseText);  // 只有當(dāng)數(shù)據(jù)返回的時候,才會調(diào)用
    })

    大規(guī)模運算帶來的耗時在Java/C#等支持多線程的語言環(huán)境中很容易實現(xiàn),而對于JavaScript/ActionScript等很難,折衷的方式是 將復(fù)雜運算延遲到服務(wù)器端進(jìn)行;或者將復(fù)雜運算拆解成若干個耗時較少的小運算,例如ActionScript的偽多線程實現(xiàn)方式。

    “一切皆異步”這個原則說來容易,但要在企業(yè)應(yīng)用中以一種一致的方式進(jìn)行實現(xiàn)很難。上例中runInAnotherThread的方式貌似簡單,也可能出 現(xiàn)在各種GUI框架的介紹中,但絕不是一個稍具規(guī)模的RichClient應(yīng)當(dāng)采用的方式。它很難作為一種編程范式被遵循,你絕不會希望看到在你的代碼中 所有用到異步的地方都new Runnable(){...}。這樣帶來的問題不僅僅是異步被不被管理的到處亂扔,還帶來了測試的復(fù)雜性。為了解決這些只有在至少有點規(guī)模的 RichClient中才出現(xiàn)的問題,你最好也實現(xiàn)了“4 線程管理”(見下篇),能夠?qū)崿F(xiàn)“3 事件管理”(見下篇)更好。終極方式是將這些抽象到應(yīng)用的基礎(chǔ)框架中,使得所有的開發(fā)人員以一種一致的方式進(jìn)行編程。

    2 視圖管理

    2.1 視圖生命周期管理

    視圖這個概念在WEB開發(fā)中幾乎被忽略。這里所說的視圖是指頁面、頁面塊等界面元素。在WEB開發(fā)中,視圖的生命周期很短:在進(jìn)入頁面的時候創(chuàng)建,在離開頁面的時候銷毀。一不小心頁面被弄糟了,或者不能按照預(yù)期的渲染了,點下刷新按鈕,整個世界一片清凈。

    WEB下的視圖導(dǎo)航也是如此自然?;诔溄拥姆绞?,每點擊一次,就能夠打開一個新的頁面,舊的頁面被瀏覽器銷毀,新的頁面誕生。(這里不考慮AJAX或者其他JavaScript特效)

    如果把這種想法帶入到RichClient開發(fā),后果會很糟糕。每當(dāng)點擊按鈕或者進(jìn)行其他操作需要導(dǎo)航到新的窗口,你不加任何限制的創(chuàng)建新窗口或者新的視 圖。然而CPU不是無限的。創(chuàng)建一個新的視圖通常是很耗CPU和內(nèi)存的。系統(tǒng)響應(yīng)會變慢。用戶會抱怨,拒絕付錢,于是因為饑餓,你的狗再次離開了你。

    每次新創(chuàng)建視圖產(chǎn)生的嚴(yán)重后果并不僅僅是非功能性的,還包括功能性的缺失。如果你用過Skype,當(dāng)你在給張三通話的時候,再次點擊張三并且進(jìn)行通話,你 會發(fā)現(xiàn)剛剛的通話界面會彈出來,而不是開啟新窗口。在我們的一個項目中,有一個功能:點擊軟件界面上的電話號碼就能開啟一個新窗口,并直接連到桌上的電話 撥號通話??梢韵胂?,如果每次都會彈出新的窗口,軟件的邏輯是根本錯誤的。

    如何解決這個問題?最簡單的方式是將所有已知的視圖全都保存到本地的一個緩存中,我們命名為ViewFactory,當(dāng)需要進(jìn)行獲取某個視圖的時候,直接從ViewFactory拿到,如果沒有創(chuàng)建,那么創(chuàng)建,并放到Cache中:

    class ViewFactory {
         cache = {}
         View getView(Object key) {
            if cache.contains(key) {
                return cache[key]
            }
            cache[key] = createView(key)
            return cache[key]  
        }
    }

    需要注意的是,ViewFactorykey的選擇。對于簡單的應(yīng)用,key可以干脆就是某個單獨窗口的類名。例如整個系統(tǒng)中往往只有一個配置窗口,那 么key就是這個類名;對于需要復(fù)用的窗口,往往需要根據(jù)其業(yè)務(wù)主鍵來創(chuàng)建相應(yīng)的視圖。例如代碼中只有一個UserDetailWindow, 需要用來展示不同用戶的信息。當(dāng)需要同時顯示兩個以上的用戶信息的時候,用同一個窗口實例顯然不對。這時候key的選擇可以是類名+用戶ID。

    2.2 視圖導(dǎo)航

    上面的方案并沒有解決導(dǎo)航的問題。導(dǎo)航需要解決的問題有兩個,如何導(dǎo)航以及如何在導(dǎo)航時傳遞數(shù)據(jù)。這時候不得不羨慕WEB的解決方式。我要訪問ID1的用戶信息,只需要訪問類似于users/1的頁面就好;需要訪問搜索結(jié)果第5頁,只需要訪問/search?q=someword&page=5就好。這里/search是視圖,q=somewordpage=5是傳遞的數(shù)據(jù)。目前我還沒有發(fā)現(xiàn)任何一本書來講述如何進(jìn)行視圖導(dǎo)航。我們的方式是實現(xiàn)一個Navigator類用來導(dǎo)航,Navigator依賴于前面提到的ViewFactory

    class Navigator {
        Navigator(ViewFactory viewFactory) {
            this.viewFactory = viewFactory;
        }
        void goTo(Object viewKey) {
            this.viewFactory.getView(viewKey).show()
        }
    }

    (這個類看起來跟ViewFactory沒什么大的差別,但他們邏輯上是完全不同,并且下面的擴(kuò)展中會增強)

    這樣是可以解決問題的。如果要在不同的視圖之間傳遞數(shù)據(jù),只需要對Navigator.goTo方法稍加擴(kuò)展,多添加一個參數(shù)就能夠傳遞參數(shù)了。例如,在用戶列表窗口點擊用戶名,發(fā)送一條消息并打開聊天窗口,可以寫為:

    void messageButton_clicked() {
        Navigator.goTo("ChatWindow#userId", "聊天消息")
    }

    然而這種方式并不完美。當(dāng)你發(fā)現(xiàn)大量的數(shù)據(jù)在窗口之間交互的時候,這種將主動權(quán)交給調(diào)用方控制的方式,會給狀態(tài)同步帶來不少麻煩;如果你使用了本地存儲,它越過存儲層直接與服務(wù)器交互的方式也會帶來不少的不便之處。更好的方式是使用“3 事件管理”(見下篇)。當(dāng)然,如果窗口之間導(dǎo)航不存在數(shù)據(jù)傳遞,基于Navigator的方式仍然簡單并且可用。

    相關(guān)閱讀:

    [ ThoughtWorks實踐集錦(1)] 我和敏捷團(tuán)隊的五個約定。

    [ ThoughtWorks實踐集錦(2)] 如何在敏捷開發(fā)中做好數(shù)據(jù)遷移。


    作者介紹:陳金洲,Buffalo AJAX中文問題 Framework作者,ThoughtWorks咨詢師,現(xiàn)居北京。目前的工作主要集中在RichClient開發(fā),同時一直對Web可用性進(jìn)行觀察,并對其實現(xiàn)保持興趣。

    給InfoQ中文站投稿或者參與內(nèi)容翻譯工作,請郵件至editors@cn.infoq.com。也歡迎大家加入到InfoQ中文站用戶討論組中與我們的編輯和其他讀者朋友交流。

    posted on 2009-03-18 09:52 二胡 閱讀(144) 評論(0)  編輯  收藏 所屬分類: JS 、web系統(tǒng)開發(fā)
    主站蜘蛛池模板: 亚洲国产天堂久久综合| 本道天堂成在人线av无码免费| 亚洲午夜无码久久久久| 国内大片在线免费看| 又大又硬又爽又粗又快的视频免费| 国产午夜亚洲精品不卡电影| 亚洲春黄在线观看| 亚洲AV一宅男色影视| 亚洲中文字幕伊人久久无码| 黄a大片av永久免费| 97在线线免费观看视频在线观看| 久久精品中文字幕免费| 黄桃AV无码免费一区二区三区| 黄页网站在线观看免费| 亚洲精品永久在线观看| 国产成人精品日本亚洲11| 亚洲精品美女在线观看| 亚洲黄色高清视频| 久久亚洲精品国产精品| 亚洲AV无码久久精品成人| 亚洲综合日韩久久成人AV| 国产精品四虎在线观看免费| 最近中文字幕mv免费高清电影| 91免费在线播放| 6080午夜一级毛片免费看| 97免费人妻在线视频| 7x7x7x免费在线观看| 99免费观看视频| 巨波霸乳在线永久免费视频| 99久久国产免费中文无字幕| 亚洲精品在线免费观看| 永久看日本大片免费35分钟| 国产人成免费视频| 日韩午夜理论免费TV影院| 免费无码黄网站在线看| a级毛片无码免费真人久久| 国产三级在线免费观看| 中文字幕版免费电影网站| 国产免费一级高清淫曰本片| 西西人体免费视频| 久操视频免费观看|