版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
本科畢業(yè)設(shè)計(jì)(論文)基于安卓的移動(dòng)課堂應(yīng)用開發(fā)學(xué)院信息工程學(xué)院 專業(yè)通信工程 年級(jí)班別2012級(jí)()班 學(xué)號(hào) 學(xué)生姓名 指導(dǎo)教師原玲2016年5月
基于安卓的移動(dòng)課堂應(yīng)用開發(fā)基于安卓的移動(dòng)課堂應(yīng)用開發(fā)姚瑤瑤信息工程學(xué)院摘要隨著計(jì)算機(jī)技術(shù)的飛速發(fā)展,一方面,各種各樣的類庫、框架層出不窮;另一方面,用戶對(duì)于軟件質(zhì)量和功能的要求也越來越高。編程工作并不像有些人聲稱的那樣,門檻變得越來越低,相反,由于系統(tǒng)變得越來越復(fù)雜,對(duì)編程人員來說,要求反而變高了。既然系統(tǒng)復(fù)雜度的增加不可避免,作為一個(gè)開發(fā)者,我們所能做的,便是尋求某些方法,以應(yīng)對(duì)這復(fù)雜的系統(tǒng)、和步步緊逼的交付日期。作為軟件工程師們的經(jīng)驗(yàn)結(jié)晶——設(shè)計(jì)模式,便是我們應(yīng)對(duì)軟件復(fù)雜度的有力武器。即便需求總是在改變,但恰如其分的軟件設(shè)計(jì),將賦予軟件足夠的彈性,去應(yīng)用合理的變化。而作為設(shè)計(jì)模式一個(gè)核心的原則——模塊化,則有助于我們分解復(fù)雜度。復(fù)雜的系統(tǒng),經(jīng)過足夠的合理的抽象、封裝,形成一個(gè)個(gè)正交的子系統(tǒng),使得開發(fā)人員能夠在同一時(shí)間只集中注意于某一個(gè)局部,而不是同時(shí)處理龐大的細(xì)節(jié)。本文根據(jù)軟件工程的一系列原則對(duì)安卓平臺(tái)的移動(dòng)課堂應(yīng)用進(jìn)行設(shè)計(jì),并對(duì)Android應(yīng)用中常用的幾種設(shè)計(jì)模式進(jìn)行比較,說明各個(gè)模式的優(yōu)劣以及設(shè)計(jì)我們的方案時(shí)所作的權(quán)衡。關(guān)鍵詞:設(shè)計(jì)模式,軟件復(fù)雜度,模塊化AbstractAsthefast-developingofcomputerscience,allkindsofsoftwareframework,librarieswereborntoeaseourdeveloplife.Butattheotherhand,ouruserswantoursoftwaretoprovidemoreandmorefunctionalitiesandexpectthatit’sstable.Thelifeofdevelopmentisnotbecomemucheasyassomebodyclaimedthatit’seasierandeasiersincetherearesomanytoolsthatwecanuse.Butthankstothecomplexityofthesystem,ourdeveloper’sskillbecomesverydemanding.Sincethecomplexityisunavoidable,wehighlyneedatooltohackwiththelargesystemandcomfortourclientsoftheincomingdeliverytime.Designpattern,asthecrystallizationoftheexperienceofourdevelopers,isanextremelypowerfularmforustofightwiththecomplexityofthesystem.Althoughtherequirementisalwayschanging,awell-designedarchitecturewillgiveoursoftwaretheabilitytocopewithsomereasonablerequirementchange.Modularity,asthecoreprincipleofdesignpattern,canhelpustodecomposethecomplexity.Usingsomereasonableandsufficientabstractionandencapsulation,thelargesystemcanbedecomposedtoseveralorthogonalsub-systems,andourdeveloperscannowdiveintosomepartbutdon'tcareothers.Inthispaper,IshowsthatthewaytodesignourAndroidmobilelearningappusingseveralbasicprinciplesofsoftwareengineering.Inaddition,IalsopresentacomparisonbetweenafewpopulardesignpatternswhiledevelopingAndroidappsandexplainourchoiceandwhychooseit..Keywords:DesignPattern,SoftwareComplexity,Modularity目錄TOC\o"1-4"\h\z\u1緒論 11.1背景 11.2什么是設(shè)計(jì)模式 11.3模式的作用 22問題 42.1一個(gè)維護(hù)噩夢(mèng) 42.2必須解決的問題 53架構(gòu)的選擇 73.1經(jīng)典的MVC模式 73.2一種變體——MVP模式 83.3更進(jìn)一步——MVVM模式 103.4回歸簡(jiǎn)樸——Document-View模式 113.5增強(qiáng)的Document-View 124框架的實(shí)現(xiàn) 144.1Document實(shí)例的創(chuàng)建 144.2View引用的保存 154.3處理配置改變引起的重復(fù)創(chuàng)建 154.4網(wǎng)絡(luò)框架 164.5總體架構(gòu) 165應(yīng)用的實(shí)現(xiàn) 185.1重新實(shí)現(xiàn)注冊(cè)頁面 185.2文件下載 196總結(jié)與展望 216.1總結(jié) 216.2展望 21參考文獻(xiàn) 22致謝 23附錄A一個(gè)簡(jiǎn)單的注冊(cè)頁面實(shí)現(xiàn) 24附錄BGenericActivity 24附錄CAbstractDocument<ViewOps> 25附錄D避免Document的重復(fù)創(chuàng)建 26附錄E下載進(jìn)度的發(fā)布 271緒論1.1背景從打孔的卡帶到匯編語言,從匯編語言到高級(jí)語言再到今天人氣高漲的人工智能,每每有新的技術(shù)出現(xiàn),總是有人預(yù)言程序員這個(gè)職業(yè)將死。然而,從六十年代高級(jí)編程語言出現(xiàn)到現(xiàn)在,程序員這個(gè)職位非但沒有消失,反倒越發(fā)的紅火。在編程所使用的工具越發(fā)強(qiáng)大的趨勢(shì)下,很多人忽略了更為重要的一點(diǎn),應(yīng)用的復(fù)雜度也在急劇攀升。人們對(duì)軟件的質(zhì)量和能力有著越來越高的期望。所以,即便是有著越來越強(qiáng)大的工具,編程這個(gè)工作也不會(huì)消亡。相反,它帶來的是越來越大的挑戰(zhàn)。應(yīng)用越來越復(fù)雜,一個(gè)簡(jiǎn)單的商業(yè)應(yīng)用,它的復(fù)雜度絕對(duì)可以輕易超過大多是程序員的智商。隔離復(fù)雜度,在軟件開發(fā)領(lǐng)域,也自然而然地成為一個(gè)不可獲取的技能。而它所使用的最大的工具,便是設(shè)計(jì)模式。模式有助于我們利用經(jīng)驗(yàn)豐富的軟件工程師的智慧,它們記錄了軟件開發(fā)領(lǐng)域已經(jīng)得到充分證明的有效經(jīng)驗(yàn),可幫助推廣良好的設(shè)計(jì)經(jīng)驗(yàn)。每個(gè)模式都一個(gè)特定的問題在特定的環(huán)境中反復(fù)出現(xiàn)的問題,并給出了一個(gè)解決方案。利用模式可以打造出具有特定特征的軟件架構(gòu)。1.2什么是設(shè)計(jì)模式ChristopherAlexander說,“每個(gè)模式描述了一個(gè)在我們身邊不斷重復(fù)發(fā)生著的問題,已經(jīng)對(duì)該問題的解決方案的核心。如此一來,你就能一次又一次地使用該方案二不必做重復(fù)勞動(dòng)”。盡管Alexander講的是建筑領(lǐng)域的模式,對(duì)于軟件建構(gòu),這個(gè)說法也同樣適用。一般而言,一個(gè)模式有4個(gè)部分:模式的名稱。用一兩個(gè)詞來描述模式的問題和效果。對(duì)一個(gè)模式命名,增加了我們的設(shè)計(jì)詞匯。模式名幫助我們思考,幫助我們與他人交流設(shè)計(jì)思想和設(shè)計(jì)結(jié)果。問題。問題描述了給定背景下反復(fù)出現(xiàn)的問題,以及在什么時(shí)候可以使用該模式。它闡述了問題的本質(zhì):必須解決的具體設(shè)計(jì)問題是什么?出來對(duì)問題的陳述,還可以輔以一系列的作用力的描述。作用力表示問題的各個(gè)方面對(duì)特定解決方案的影響。解決方案。解決方案描述了該如何解決上述重復(fù)出現(xiàn)的問題,或者說,如何平衡相關(guān)的作用力。它描述了設(shè)計(jì)的各個(gè)組件之間的關(guān)系和各自的職責(zé)。因?yàn)槟J骄拖褚粋€(gè)模板,它可用于解決一定條件下重復(fù)出現(xiàn)的不同問題,所以解決方案并不描述一個(gè)特定的設(shè)計(jì)或者實(shí)現(xiàn),而是提供一個(gè)更為抽象的概念,并對(duì)軟件設(shè)計(jì)進(jìn)行描述。效果。效果描述了應(yīng)用一個(gè)模式所能夠達(dá)到的效果已經(jīng)該模式所權(quán)衡的問題。它對(duì)于如何評(píng)價(jià)設(shè)計(jì)、選擇使用何種模式已經(jīng)選擇該模式的代價(jià)具有重要意義。模式的作用模式描述了在特定環(huán)境下反復(fù)出現(xiàn)的問題,并提供了該問題的一個(gè)解決方案。模式記錄了已經(jīng)得到充分驗(yàn)證的既有的設(shè)計(jì)經(jīng)驗(yàn)。模式并非刻意發(fā)明或創(chuàng)造出來的,而是工程師們根據(jù)其自身的經(jīng)驗(yàn)提煉出來的。模式描述了超越類、實(shí)例和組件的抽象。由于模式是用于解決特定一類問題的通用的解決方案,這就決定了其不能描述具體的實(shí)現(xiàn),而必須在更高的抽象上描述問題。模式常常描述了多個(gè)組件、類或?qū)ο笾g的協(xié)作方式和各自的職責(zé)。通過對(duì)象間的協(xié)作,從而解決該問題。模式提供了一種通用的語言,并讓大家對(duì)設(shè)計(jì)原則有一致的認(rèn)識(shí)。精心選擇的模式名會(huì)成為廣外人知的設(shè)計(jì)語言的一部分,有助于對(duì)設(shè)計(jì)問題及其解決方案展開有效的討論。我們不需要對(duì)解決方案給出詳盡的描述,只要提及其模式名,熟悉該模式的人便能夠馬上明白程序的基本結(jié)構(gòu)和特征。模式是一種記錄軟件架構(gòu)的手段。模式可描述你在設(shè)計(jì)軟件系統(tǒng)時(shí)腦海中浮現(xiàn)的構(gòu)思,在別人擴(kuò)展和修改原始架構(gòu)或修改系統(tǒng)的代碼時(shí),這有助于避免違背這種構(gòu)思。模式有助于創(chuàng)建具有指定特征的軟件。模式提供了功能行為骨架,有助于實(shí)現(xiàn)應(yīng)用程序的功能。每一種模式都有描述了使用該模式所能夠達(dá)到的效果,這基本上就覺得了應(yīng)用該模式的軟件會(huì)成長(zhǎng)為什么樣。模式有助于打造復(fù)雜而異質(zhì)的軟件。每個(gè)模式都描述了一組預(yù)定義的組件,這些組件扮演的角色以及它們之間的關(guān)系,可用于規(guī)范軟件結(jié)構(gòu)的特定方面。模式猶如建筑構(gòu)件,可用于打造更復(fù)雜的設(shè)計(jì)。模式有助于控制軟件的復(fù)雜度。每個(gè)模式都為其闡述的問題提供了經(jīng)過實(shí)踐考驗(yàn)的解決之道:需要的組件類型、這些組件扮演的角色、應(yīng)隱藏的細(xì)節(jié)、令人矚目的抽象,已經(jīng)各個(gè)部分的原理。通過明確各個(gè)組件的角色以及它們之間的關(guān)系,在軟件開發(fā)過程中,我們可以僅僅關(guān)注一個(gè)單獨(dú)的組件,而不需要花費(fèi)多余的精力去考慮整個(gè)系統(tǒng)。2問題2.1一個(gè)維護(hù)噩夢(mèng)考慮一下我們正在編寫的Android移動(dòng)課堂應(yīng)用?,F(xiàn)在,我們需要用戶最先看到的頁面——注冊(cè)。對(duì)于一個(gè)最簡(jiǎn)單的注冊(cè)頁面,我們需要兩個(gè)輸入框,一個(gè)按鈕,待用戶輸入用戶名和密碼后,我們獲取對(duì)應(yīng)的信息,然后發(fā)送至后臺(tái)服務(wù)器。然后,對(duì)于很多的新手,不出意外的,寫出的代碼(見附錄A)卻幾乎可以肯定會(huì)包含一系列的問題。首先,我們可以肯定的是,那段代碼的邏輯并沒有什么問題——在onCreate方法中初始化View并為按鈕注冊(cè)事件監(jiān)聽器。然后,由于Android并不允許在主線程中執(zhí)行網(wǎng)絡(luò)操作,我們新開了一個(gè)單獨(dú)的線程,用以將注冊(cè)信息發(fā)往服務(wù)器。但是,遺憾的是,這段代碼存在著非常嚴(yán)重的問題:Activity的引用泄露到的匿名內(nèi)部類的Runnable實(shí)例中,這幾乎可以肯定會(huì)發(fā)生內(nèi)存泄露,進(jìn)而發(fā)生臭名昭著的OurOfMemoryError錯(cuò)誤。為了解決問題1,我們可以將Runnable實(shí)現(xiàn)為靜態(tài)的內(nèi)部類,如此一來,便不會(huì)意外地將Activity的引用泄露出去。但是,如果一來,為了在服務(wù)器將注冊(cè)結(jié)果返回的時(shí)候做出反應(yīng),并對(duì)UI做出相應(yīng)的改變,我們需要同時(shí)使用WeakReference和Handler。用戶每點(diǎn)擊按鈕一次,便新創(chuàng)建一個(gè)線程。這必將使應(yīng)用經(jīng)受大量的線程創(chuàng)建和銷毀帶來的開銷。這將使得應(yīng)用和整個(gè)系統(tǒng)運(yùn)行緩慢,而我們的用戶,也將會(huì)由于無法忍受這體驗(yàn)而永遠(yuǎn)不再使用這款A(yù)PP。也許,你聽說過Java的ExecutorFramework。沒錯(cuò),我們可以利用它減少線程創(chuàng)建、銷毀的開銷。但是,即便使用線程池,問題1和2的描述也依然適用。有經(jīng)驗(yàn)的開發(fā)者會(huì)發(fā)現(xiàn)另外一個(gè)非常嚴(yán)重的問題。這里,應(yīng)用的UI和邏輯混合在了一起。應(yīng)用的邏輯通常不會(huì)發(fā)生太多的改變,而UI卻往往是改動(dòng)之源。雖然改動(dòng)UI不一定就會(huì)修改到邏輯,如果我們足夠小心,也可以保證在更新UI的同時(shí),不會(huì)意外地給邏輯部分的代碼引入bug。但是,既然他們?cè)谕粋€(gè)文件里,而你打開了那個(gè)文件進(jìn)行修改,那么,就存在破壞的可能。最安全的做法是,將邏輯部分隔離開,同一時(shí)間,我們只關(guān)注UI或邏輯(所謂的隔離復(fù)雜度),這樣,在改變UI的時(shí)候,我們可以保證邏輯部分不會(huì)遭到破壞。同時(shí),將UI和邏輯分離,對(duì)于應(yīng)用對(duì)編寫也有非常大的益處。同一時(shí)間,我們需要關(guān)注的東西更少了。注意力的集中,意味著我們可以專注于更細(xì)的細(xì)節(jié)上,編寫出更好、更健壯的應(yīng)用。現(xiàn)在,跳出這么一個(gè)單獨(dú)的Activity,讓我們考慮一整個(gè)應(yīng)用——我們的Android移動(dòng)課堂應(yīng)用。不出意外,幾乎每一個(gè)頁面,都會(huì)有網(wǎng)絡(luò)操作。換句話說,即便根據(jù)上面的討論,我們修復(fù)了附錄A中所展示的代碼的bug,采用這種方法,也必將存在大量的重復(fù)代碼。這嚴(yán)重得違反了DRY原則,必將導(dǎo)致一個(gè)維護(hù)的噩夢(mèng)。2.2必須解決的問題前面我們說到,設(shè)計(jì)模式的組成的問題部分,描述的是一個(gè)特定背景下反復(fù)出現(xiàn)的問題,并且,對(duì)于該問題的描述不應(yīng)該針對(duì)特定的應(yīng)用,它應(yīng)該在更為抽象的層級(jí)上描述一個(gè)反復(fù)出現(xiàn)的問題。上一小節(jié)我們討論對(duì)于一個(gè)特定的注冊(cè)頁面的面臨的問題。實(shí)際上,不只是那一個(gè)頁面,我們所開發(fā)的移動(dòng)課堂APP,幾乎所有的頁面都存在著相似的問題。更進(jìn)一步講,所有需要和服務(wù)器進(jìn)行通信的APP都將面對(duì)這同一個(gè)問題。但凡是一個(gè)較長(zhǎng)時(shí)間的操作,例如網(wǎng)絡(luò),我們都要小心避免泄露Activity的引用。但是,我們也不想在每個(gè)命令對(duì)象中使用WeakReference。因?yàn)?,這所有的弱引用,都是為了同一個(gè)目的而存在——保存Activity的引用。既然使用他們的目的是一致的,那么,我們就完全有理由用一個(gè)復(fù)用的組件來完成這一功能。在上面我們的提到了UI和邏輯分離的原則。雖然“分離”二字很簡(jiǎn)單,并且做起來,也似乎不難做到將應(yīng)用的UI和邏輯分開。但是,我們要做的不僅僅是分離,而是一致地分離。我們希望整個(gè)應(yīng)用有一致的架構(gòu),我們希望底層組件能夠得到盡可能多的復(fù)用。也就是說,對(duì)于類似的頁面,我們希望可以有一種全局性的架構(gòu),不管UI的內(nèi)容和類型,它都能夠勝任。對(duì)于UI和邏輯分離的問題,我們希望不僅僅是通過口頭或者文檔的形式進(jìn)行約束。如果一個(gè)對(duì)框架的使用存在錯(cuò)誤的用法,那么,錯(cuò)誤就一定會(huì)發(fā)生。所以,我們希望在選定了框架之后,能夠從語法層面約束使用者。我們需要有強(qiáng)制性的措施,以避免用戶出錯(cuò)。同時(shí),對(duì)于UI和邏輯分離的問題,我們需要引導(dǎo)用戶以分離的思維去考慮應(yīng)用的設(shè)計(jì),并使用框架實(shí)現(xiàn)強(qiáng)制用戶進(jìn)行分離。可是,世上并沒有銀彈。盡管我們希望構(gòu)件一個(gè)全局性的架構(gòu),以期提供整體的一致性。其實(shí)我們并沒有辦法實(shí)現(xiàn)一個(gè)架構(gòu),使得它能夠適用于所有的場(chǎng)景。但是,我們能夠做到的是,盡可能地讓其可擴(kuò)展。只要擁有足夠的擴(kuò)展性,它就能夠適應(yīng)更多的應(yīng)用場(chǎng)景,也就能夠解決更多的問題。更進(jìn)一步,如果在這所有問題中存在著一個(gè)子集,它們需要一種更為特化的解決方案,我們可以對(duì)原有的基礎(chǔ)框架進(jìn)行擴(kuò)展,從而用這個(gè)新的特化的框架來決定這些問題。此外,我們也希望它足夠地輕量,它僅僅解決最為核心的、一直重復(fù)著的問題。而不試圖提供過多無謂的功能。一個(gè)好的設(shè)計(jì),是已經(jīng)不能夠再減少任何東西。3架構(gòu)的選擇3.1經(jīng)典的MVC模式提起UI和邏輯的分離,相信很多人最先想到的便是MVC(Model-View-Controller)模式了。從Smalltalk時(shí)代開始,MVC便被用來創(chuàng)建用戶界面。在MVC模式里,共包含三種類型的對(duì)象,模型Model是應(yīng)用對(duì)象,視圖View用于向用戶展示,而控制器Controller定義了View對(duì)于用戶輸入的響應(yīng)方式。不使用MVC時(shí),用戶界面設(shè)計(jì)往往將這些對(duì)象混雜在一起,不利于提供設(shè)計(jì)的靈活性和復(fù)用性。MVC通過同時(shí)使用觀察者模式和策略模式分離視圖和模型,同時(shí)提供對(duì)不同UI邏輯的支持。同時(shí)建立一個(gè)“訂閱/通知”協(xié)議,視圖和模型彼此分離。視圖必須保證它的顯示正確地反映了模型的狀態(tài)。一定模型發(fā)送了變化,它也將通知視圖,從而,視圖可以以此作為契機(jī),更新對(duì)應(yīng)的UI。模型的變更傳播機(jī)制確保應(yīng)用程序的數(shù)據(jù)發(fā)生變化時(shí),所有的觀察者將在正確的時(shí)間得到通知。這讓所有依賴于模型的視圖和控制器得以同步。這種方法還可以讓你為一個(gè)模型提供不同的多個(gè)視圖的表現(xiàn)形式,為能夠?yàn)橐粋€(gè)模型創(chuàng)建新的視圖而無需重寫模型。在運(yùn)行階段,可同時(shí)打開多個(gè)視圖(共享一個(gè)model),還可以動(dòng)態(tài)地打開和關(guān)閉視圖。圖3.1MVC模式而對(duì)于View和Controller,則是策略模式的一個(gè)例子。一個(gè)策略表示一個(gè)算法族的一個(gè)對(duì)象。通過定義一個(gè)算法族,我們可以動(dòng)態(tài)或靜態(tài)地替換對(duì)應(yīng)的策略。而策略的使用者——這里的視圖,則完全不受影響。通過將模型、視圖和控制器分離,可更換模型的視圖和控制器,甚至在運(yùn)行階段都可以替換用戶界面。但是,對(duì)于當(dāng)今的移動(dòng)開發(fā),MVC模式又有一些顯著的不足。首先,MVC三個(gè)組件存在著一個(gè)環(huán)狀的依賴關(guān)系。也就是說,一個(gè)組件接口的變化,必將同時(shí)影響另外兩個(gè)組件。不僅如此,環(huán)狀依賴也提高了單元測(cè)試的難度。同一時(shí)間,如果我們想對(duì)一個(gè)組件進(jìn)行測(cè)試,必須提供兩個(gè)mock對(duì)象。此外,視圖和控制器的關(guān)系過于緊密??刂破骱鸵晥D雖然分開了,但關(guān)系緊密,這導(dǎo)致無法分別重用它們。不僅如此,視圖和控制器與模型也是緊耦合的。視圖和控制器都直接調(diào)用模型,這意味著修改模型的接口將破壞視圖和控制器的代碼。3.2一種變體——MVP模式由于上述MVC模式的一系列問題,加之其誘人的優(yōu)點(diǎn),于是,便有了它的一個(gè)變體——MVP模式。MVP作為一個(gè)面向用戶界面設(shè)計(jì)的架構(gòu)模式,被刻意設(shè)計(jì),以充分利用一些自動(dòng)化單元測(cè)試工具并且改善表現(xiàn)邏輯分離的問題。圖3.2MVP模式 在MVP模式中,模型Model組件提供了一個(gè)定義用于展示的數(shù)據(jù)的接口,并根據(jù)用戶的動(dòng)作做出相應(yīng)的處理邏輯。這里的Model和MVC中的Model并沒有什么差異。而表現(xiàn)者Presenter則作為一個(gè)中間人的角色而存在,所有的表現(xiàn)邏輯都存在于表現(xiàn)者Presenter中。它從Model中取得數(shù)據(jù),并對(duì)它進(jìn)行格式化,然后在View中展示。所以,Presenter也因此有了另一個(gè)名稱——超級(jí)控制器。對(duì)于最后的View組件,這里我們稱它為被動(dòng)視圖。視圖并不主動(dòng)處理UI的更新和用戶動(dòng)作,它所做的,就是非常單一的功能——展示用戶界面。視圖的更新由Presenter復(fù)制,對(duì)于用戶的動(dòng)作,它也是直接轉(zhuǎn)發(fā)至Presenter中。 實(shí)際上,對(duì)于視圖所處理的邏輯的多少,每個(gè)不同的實(shí)現(xiàn)都不盡相同。在一個(gè)極端,視圖是一個(gè)完全的被動(dòng)式的存在,將所有的用戶操作都轉(zhuǎn)發(fā)至Presenter中。在這種情況下,當(dāng)用戶觸發(fā)View組件的一個(gè)事件回調(diào)時(shí),它不會(huì)做任何的處理,而僅僅是調(diào)用presenter的一個(gè)沒有參數(shù)也沒有返回值的方法。然后,Presenter通過View組件的接口,取出必需的數(shù)據(jù)。最后,Presenter操作Model組件,得到結(jié)果后又相應(yīng)地更新UI。而在另一方面,某些實(shí)現(xiàn)卻運(yùn)行View組件處理某些特定的事件、操作或命令。這通常更適用于基于web的架構(gòu),這種情況下,View組件通常運(yùn)行在用戶的瀏覽器中,所以,對(duì)于一些交互命令,View組件是一個(gè)更好的處理場(chǎng)所。 MVP模式與MVC模式最大的不同在于,MVP并不存在環(huán)狀依賴,取而代之,MVP是鏈狀的依賴關(guān)系。這使得MVP更加地適合于單元測(cè)試。同時(shí),由于Presenter的存在,即便Model的接口發(fā)生變化,我們也只需要修改Presenter——我們的View組件,依然可以繼續(xù)使用而不需要做任何的修改。而對(duì)于MVC的優(yōu)點(diǎn),在這里也同樣保持著。我們的UI和邏輯是顯著分離的,組件也可以復(fù)用。如果交換邏輯需要作出修改,也可以通過替換Presenter這個(gè)組件而得到所需的效果。同時(shí),這里的Presenter也是作為一個(gè)策略而存在的,這意味著,我們可以在運(yùn)行時(shí)動(dòng)態(tài)地更換表現(xiàn)邏輯。 遺憾的是,MVP也有其缺點(diǎn)。前面我們說MVP是鏈狀依賴的時(shí)候,敏銳的你就應(yīng)該意識(shí)到,我們的調(diào)用鏈過長(zhǎng)了。即使是Model中的一個(gè)小小的改變,也要跨過千山萬水才能夠表現(xiàn)在UI上。也就是說,與MVC相比,對(duì)于性能很關(guān)心的應(yīng)用,這個(gè)模式可能就不太適用了。所幸的是,這種情況發(fā)生的幾率實(shí)在太低,所以一般不會(huì)是太大的問題。而更為致命的是,作為超級(jí)控制器的Presenter,對(duì)于UI的所有更新都要經(jīng)手的它,實(shí)現(xiàn)中往往存在很多的盲轉(zhuǎn)發(fā)。大多數(shù)時(shí)候,我們根本不需要對(duì)數(shù)據(jù)進(jìn)行格式化,只是從Model取出,然后直接應(yīng)用于View組件的更新。編寫這么多的盲轉(zhuǎn)發(fā)代碼,可不會(huì)是一件愉快的事。3.3更進(jìn)一步——MVVM模式前面我們提到MVP模式中,將數(shù)據(jù)顯示到View組件通常是一件比較無趣而繁瑣的工作。而MVVM(Model-View-ViewModel)的出現(xiàn),就是為了解決這么一個(gè)問題。MVVM同樣是對(duì)圖形用戶界面與應(yīng)用邏輯的分離。它通過一種標(biāo)記語言或GUI代碼,將UI與商業(yè)邏輯或后臺(tái)邏輯分離開。MVVM中的ViewModel組件是一個(gè)值轉(zhuǎn)換器;這意味著ViewModel的職責(zé)是從將Model類得來的數(shù)據(jù)對(duì)象進(jìn)行轉(zhuǎn)化,使之更易于管理和表現(xiàn)。從這一點(diǎn)看,ViewModel比View組件更加的模型化,并處理著幾乎所有的視圖表現(xiàn)邏輯。ViewModel可以使用中間人模式進(jìn)行實(shí)現(xiàn),它處理View所支持的所有對(duì)后端邏輯的訪問控制。Model-View-ViewModel也叫Model-View-Binder,因?yàn)閷?duì)View組件的更新,我們通常通過一些自動(dòng)化的工具進(jìn)行,也就是所謂的databinding。圖3.3MVVM模式從組件的依賴關(guān)系上看,MVVM和MVP非常地相似,唯一的不同是,MVP里,我們程序員自己手動(dòng)執(zhí)行了一個(gè)所謂databinding的動(dòng)作。Model組件也叫domainmodel,與MVC和MVP中的Model一樣,這里用于表現(xiàn)業(yè)務(wù)邏輯,并提供應(yīng)用數(shù)據(jù)的存取。View組件也是,作為一個(gè)用戶界面而存在。ViewModel是View組件的一個(gè)抽象表示,用于暴露其公開的接口。與MVC中的Controller和MVP中的Presenter不同的是,MVVP有一個(gè)binder。在ViewModel中,binder調(diào)節(jié)著View和ViewModel的通信。聲明式的對(duì)數(shù)據(jù)、命令和UI的綁定在MVVM模式中是隱式的。Binder將開發(fā)者從手工編寫大量模板代碼解放出來。毫無例外,MVVM也有其缺點(diǎn)。對(duì)簡(jiǎn)單的應(yīng)用而已,這樣的框架無意過于的厚重。而對(duì)于復(fù)雜的交互邏輯,靠程序(binder)進(jìn)行自動(dòng)的數(shù)據(jù)綁定又顯得過于的力不從心。使用MVVM時(shí),我們得自行拿捏一個(gè)中庸之道。3.4回歸簡(jiǎn)樸——Document-View模式MVC存在著環(huán)狀依賴,MVP調(diào)用鏈過長(zhǎng),MVVM對(duì)簡(jiǎn)單應(yīng)用過于復(fù)雜,對(duì)復(fù)雜應(yīng)用支持又不足,那么,我們又應(yīng)該選擇哪一個(gè)模式呢?回想前面我們討論過的問題,我們需要的是UI和邏輯分離,需要它足夠的輕量,并具有相當(dāng)?shù)目蓴U(kuò)展性。它只解決最為迫切,一直重復(fù)發(fā)生著的問題。那么,這樣的架構(gòu)模式存不存在呢?答案是,存在,它就是所謂的Document-View模式。圖3.4Document-View模式Document-View也是屬于MVC變體的一種。這里的View,和MVC中的View并沒有什么顯著的差別,同樣的用于向用戶展示信息和提供交互。而Document則相當(dāng)于Model和Controller的結(jié)合,或者說,MVP模式中的Model和Presenter。使用Document-View模式的最為著名的架構(gòu),應(yīng)該就屬微軟的MFC框架了。默認(rèn)情況下,MFC的項(xiàng)目生成向?qū)?huì)生成兩個(gè)類——Document類和View類。Document負(fù)責(zé)管理數(shù)據(jù)并更新View,View組件則用于向用戶展示數(shù)據(jù)和提供交互功能。這就是我們所需要的最基本的UI和應(yīng)用邏輯分離。但是,如果僅僅是UI和邏輯分離,并不足以使我們選擇這么一個(gè)架構(gòu)。選擇Document-View,還有著更多的理由。對(duì)于絕大多數(shù)的Android應(yīng)用,一個(gè)Model僅僅對(duì)應(yīng)一個(gè)View,我們并沒有不需要MVC同步更新多個(gè)View組件的功能。如果使用MVC,卻要因此忍受它帶來的環(huán)狀依賴。可以說,MVC并不適用于Android應(yīng)用的開發(fā)。MVP有著過長(zhǎng)的調(diào)用鏈,無論是從View到Model還是從Model到View,我們不想要這些額外的消耗。對(duì)于性能非常重要的應(yīng)用而已,中間的Presenter是不能忍受的。此外,很多時(shí)候,中間的Presenter并沒有做太大有用的工作,它只是單純地將View和Model的調(diào)用相互轉(zhuǎn)發(fā)而已。對(duì)于MVVM,不使用他的原因和上面所述的它的缺點(diǎn)一樣。在簡(jiǎn)單的應(yīng)用表現(xiàn)不佳,復(fù)雜的應(yīng)用卻有力不從心。最為重要的一點(diǎn)是,由于它們都是基于UI和邏輯分離的原則所設(shè)計(jì)的,四個(gè)模式都有其共通的地方。而對(duì)于最簡(jiǎn)單的Document-View,它提供了最為基本的UI分離的支持,使用它,在合適的場(chǎng)合,我們可以輕易對(duì)它進(jìn)行擴(kuò)展,以增強(qiáng)為其他模式。假定我們現(xiàn)在的UI交換邏輯過于的復(fù)雜,Document-View已經(jīng)無法滿足我們的需求。此時(shí),我們可以對(duì)Document-View進(jìn)行擴(kuò)展,使之成為一個(gè)MVP模式。需要注意的一點(diǎn)是,盡管此時(shí)已經(jīng)變化為MVP模式,但我們還是重用了低層Document-View框架的實(shí)現(xiàn)。圖3.5將Document-View擴(kuò)展為MVP模式3.5增強(qiáng)的Document-View在前面我們描述模式的時(shí)候,我們通常都只是說“View”,“Model”等等。即便我們使用這樣的術(shù)語,但是,這并不意味著,各個(gè)組件是在和實(shí)體的類進(jìn)行交談。這里“View”,并不特指某個(gè)具體的實(shí)現(xiàn),它完全可以是一個(gè)接口。目前Android的Native應(yīng)用主要是使用Java進(jìn)行開發(fā)的,利用Java的語言特性,我們完全可以做得更好。圖3.6增強(qiáng)的Document-View這里的I指的是Interface,并且,這里的interface并不指一般意義上的接口,而是指Java語言的一個(gè)語法“interface”。組件并不互相直接就進(jìn)行通信,而是通過引用一句接口。通過針對(duì)接口進(jìn)行編程,我們保留了對(duì)組件進(jìn)行透明替換的能力。雙方通過接口進(jìn)行引用,使得在利用對(duì)方提供的接口時(shí),只能使用接口所提供的抽象,這大大減少了需要同時(shí)關(guān)注的問題,很好地隔離了復(fù)雜度。接口提供了一個(gè)語言級(jí)的支持,可以實(shí)現(xiàn)安全、透明的實(shí)現(xiàn)替換。我們并不關(guān)心View和Document的實(shí)際類型是什么,我們只知道,那個(gè)類實(shí)現(xiàn)了我們所需的接口。只有實(shí)現(xiàn)對(duì)應(yīng)的接口,我們就可以對(duì)一個(gè)組件進(jìn)行直接的替換,而另一個(gè)組件則完全不用更改。甚至,與MVC、MVP等提供的動(dòng)態(tài)性一樣,我們也可以在運(yùn)行時(shí)動(dòng)態(tài)地選擇View和Document的實(shí)現(xiàn)。定義接口的過程中,可以迫使我們對(duì)組件所需要提供的功能進(jìn)行細(xì)致的考慮。通過對(duì)業(yè)務(wù)進(jìn)行分析并制定接口,可以避免在尚不清楚邏輯的情況下過快地進(jìn)行編程。同時(shí),它也可以幫助我們理清應(yīng)用的邏輯。還應(yīng)注意的是,接口的命名應(yīng)該是描述式的,它表明所完成的功能,而不是如何完成該功能。當(dāng)我們編寫實(shí)體類的時(shí)候,只需要實(shí)現(xiàn)對(duì)應(yīng)的接口,此時(shí)不再需要理會(huì)另一個(gè)組件是如何實(shí)現(xiàn)的。4框架的實(shí)現(xiàn)4.1Document實(shí)例的創(chuàng)建Android的UI是基于所謂的Activity實(shí)現(xiàn)的,一個(gè)Activity就相當(dāng)于一個(gè)窗口。所以,很自然的,Activity就是我們Document-View架構(gòu)中View組件的實(shí)現(xiàn)者了。由于一個(gè)Android應(yīng)用首先啟動(dòng)的幾乎總是Activity,并且它是由AndroidRuntime啟動(dòng)的,所以,剩下的我們需要關(guān)心的,表示何時(shí)實(shí)例化Document的實(shí)例,又在哪里進(jìn)行實(shí)例化。每個(gè)Activity都對(duì)應(yīng)有一個(gè)Document,一般情況下,在Activity::onCreate方法中對(duì)Document實(shí)例化后,我們將其引用放置于內(nèi)部的一個(gè)實(shí)例域中。而這一系列的步奏,無疑每個(gè)Activity都需要。此時(shí),就是拿出繼承這把武器的時(shí)候了。通過使用泛型參數(shù),我們不再需要提供一個(gè)公共的Document或View接口,而是由Java編譯器幫助我們進(jìn)行安全的類型轉(zhuǎn)換。也就是說,子類所提供的Document和View接口的類型得以保留。由于我們希望由超類統(tǒng)一對(duì)Document進(jìn)行實(shí)例化,在此,我們不得不做出一些折衷。在我們的實(shí)現(xiàn)中,我們要求Document類具有一個(gè)默認(rèn)構(gòu)造函數(shù),從而可以利用Class::instance()方法進(jìn)行實(shí)例的創(chuàng)建。具體的實(shí)現(xiàn)代碼見附錄B。與此同時(shí),由于我們需要將View引用傳遞給Document,這里我們必須對(duì)Document的接口進(jìn)行一定的約束。也就是說,Document接口有一個(gè)公共的祖先BasicDocumentOps接口。publicinterfaceBasicDocumentOps<ViewOps>{voidonCreate();voidonDestroy();voidsetView(ViewOpsview);} 通過增加一個(gè)setView方法,我們可以利用它設(shè)置View組件的引用。同時(shí),我們也增加了兩個(gè)用于Activity聲明周期回調(diào)的方法。 使用該超類時(shí),子類只需要回調(diào)超類的onCreateDocument方法,GenericActivity即會(huì)自動(dòng)完成Document的創(chuàng)建工作: onCreateDocument(view,RegisterDocument.class);4.2View引用的保存前面我們提到了Activity的View組件的天然候選人,而在一開始我們就也提到了不小心保存Activity的引用會(huì)導(dǎo)致內(nèi)存泄露的問題。也就是說,對(duì)于傳遞給Document的實(shí)例,我們必須使用WeakReference將其保存起來,否則,將很容易發(fā)生內(nèi)存泄露。而這樣的一個(gè)處理措施,同樣是所有Document都必須具備的。由于有了上面創(chuàng)建Document時(shí)的經(jīng)驗(yàn),我們很容易就會(huì)想要使用基于繼承的方法來做。每次,這里我們確實(shí)用的是繼承,但由于接口由于抽象類。對(duì)于Document,我們只是給出一個(gè)骨架實(shí)現(xiàn),如果客戶需要,他可以完全不使用我們這里所創(chuàng)建的類型體系。具體的代碼見附錄C。理論上,我們好像可以依靠onDestroy回調(diào)來釋放view組件。而實(shí)際上,我們并不能這么做。因?yàn)槲覀儧]有辦法強(qiáng)制客戶在不需要Document實(shí)例的時(shí)候,來調(diào)用外面的onDestroy方法。因此,為了防止內(nèi)存泄露,這里我們必須使用WeakReference。此外,由于view引用是通過setView方法而不是在構(gòu)造函數(shù)中設(shè)置的,我們沒有辦法使用final域所提供的內(nèi)存可見性保證,所以這里我們將其設(shè)置為volatile,從而確保Document組件中的后臺(tái)線程能夠看到mReference域的變化。4.3處理配置改變引起的重復(fù)創(chuàng)建 默認(rèn)情況下,當(dāng)手機(jī)屏幕旋轉(zhuǎn)時(shí),AndroidRuntime會(huì)自動(dòng)銷毀當(dāng)前的Activity并重建一個(gè)。此時(shí),對(duì)于我們的Document-View架構(gòu)來說,按照之前的實(shí)現(xiàn),勢(shì)必將會(huì)導(dǎo)致Document組件也重新創(chuàng)建。然而,一般情況下,這種創(chuàng)建確實(shí)完全不必要的。 為了避免Document組件的重復(fù)創(chuàng)建問題,我們可以利用Android的Fragment組件。只有設(shè)置fragment.setRetainInstance(true),當(dāng)由于配置改變發(fā)生Activity的銷毀重建時(shí),該fragment并不會(huì)被銷毀。然后,通過FragmentManager我們可以重新獲取該對(duì)象。只要我們將Document放置于Fragment中,便可以避免Document的重復(fù)創(chuàng)建。 實(shí)現(xiàn)代碼見附錄D。4.4網(wǎng)絡(luò)框架基于不重復(fù)制造輪子的原則,我們使用了OkHttp3作為網(wǎng)絡(luò)框架。OKHttp3提供了同步和異步兩種調(diào)用接口:使用同步接口時(shí),客戶需要自己處理并發(fā)問題使用異步接口時(shí),框架根據(jù)傳輸層協(xié)議的成功與否,調(diào)用相應(yīng)的回調(diào)函數(shù)。由于我們并不想自己處理線程,并且其所提供的異步編程接口能夠滿足我們的需求,所以便直接使用了其異步編程接口。這里有一點(diǎn)值得一提的是,回調(diào)是在后臺(tái)線程執(zhí)行的。這個(gè)做法是必須的。當(dāng)HTTP響應(yīng)可讀時(shí),回調(diào)函數(shù)即會(huì)執(zhí)行。這里的一個(gè)優(yōu)點(diǎn)是,我們可以對(duì)響應(yīng)進(jìn)行耗時(shí)較長(zhǎng)的操作,而不會(huì)影響應(yīng)用的響應(yīng)度。缺點(diǎn)則是,我們無法直接將結(jié)果發(fā)布至UI線程。為了應(yīng)對(duì)這個(gè)不足,可能的做法是:使用裝飾器模式,編寫一個(gè)裝飾器。裝飾器在這里所做的,便是將回調(diào)轉(zhuǎn)發(fā)至UI線程執(zhí)行。由于回調(diào)執(zhí)行時(shí),讀取操作仍然會(huì)阻塞,所以這幾乎不會(huì)是什么好方法。應(yīng)用適配器模式,我們重新定義一個(gè)回調(diào)接口,在后臺(tái)線程讀取完所有的數(shù)據(jù)后,再將數(shù)據(jù)傳遞至非阻塞接口。這個(gè)其實(shí)也是另一個(gè)網(wǎng)絡(luò)框架Volley的做法。但它有一個(gè)致命的缺點(diǎn)——不能用于數(shù)據(jù)量巨大的網(wǎng)絡(luò)請(qǐng)求,如文件下載。這個(gè)也是Volley沒有提供文件上傳、下載功能的原因。直接發(fā)布結(jié)果至View組件,由View組件自己進(jìn)行線程同步。這個(gè)是我們所采用的方法。原因是,上面兩種做法都預(yù)先假定了View層不是線程安全的。這違反了信息隱藏的原則。在我們的Document-View架構(gòu)中,兩種僅僅是通過接口引用對(duì)方,我們不希望對(duì)對(duì)方的實(shí)現(xiàn)有過多的猜測(cè)。它們只需要關(guān)系自己如何實(shí)現(xiàn)即可。此外,假定View組件不是線程安全的,這個(gè)做法本身也值得懷疑。假使某天我們的應(yīng)用移植到了一個(gè)命令行界面,那我們還需要對(duì)UI做這么多的同步嗎?換句話說,只有View組件了解自己,只有它自己知道如何進(jìn)行同步,所以,同步操作應(yīng)該交由View組件自己去實(shí)現(xiàn)。4.5總體架構(gòu)在OkHttp3的基礎(chǔ)上,整個(gè)應(yīng)用實(shí)際上形成了一個(gè)分層架構(gòu)。實(shí)際上,Document-View也僅僅是分層架構(gòu)的一個(gè)特例而已。圖4.1整體架構(gòu)5應(yīng)用的實(shí)現(xiàn)利用我們前面所實(shí)現(xiàn)的Document-View框架,整個(gè)應(yīng)用具體非常一致的結(jié)構(gòu)。所以,這里僅僅是選取兩個(gè)比較典型的例子對(duì)實(shí)現(xiàn)部分進(jìn)行說明。5.1重新實(shí)現(xiàn)注冊(cè)頁面首先,我們需要定義兩個(gè)Document-View的接口:interfaceRegisterViewOpsextendsOnDocumentFail{voidonRegisterSuccess(Stringemail,Stringpassword);voidonRegisterFail();voidonNetworkError();}interfaceRegisterDocumentOpsextendsBasicDocumentOps<RegisterViewOps>{voidonRegister(Stringname,Stringemail,Stringpassword);}這里需要注意的是,方法的名詞應(yīng)該只與應(yīng)用邏輯相關(guān)。我們絕對(duì)不應(yīng)該對(duì)雙方的實(shí)現(xiàn)做出過多的假設(shè)。然后,在相應(yīng)的事件發(fā)生時(shí),調(diào)用對(duì)應(yīng)的接口:publicvoidonClick(Viewv){getDocument().onRegister(…)}publicvoidonRegisterSuccess(finalStringemail,finalStringpassword){runOnUiThread(newRunnable(){publicvoidrun(){//dowhateveryouneeded}});}當(dāng)用戶點(diǎn)擊“注冊(cè)”按鈕時(shí),我們直接調(diào)用Document的onRegister方法,然后就只是靜靜地等待結(jié)果返回。當(dāng)結(jié)果返回的時(shí)候,我們通過Activity的runOnUiThread方法進(jìn)行線程的同步。而對(duì)于Document也是一樣的,它只需要實(shí)現(xiàn)兩個(gè)接口,其余的一概不需要過問:publicvoidonRegister(Stringname,Stringemail,Stringpassword){//posttheregisterinfousingOkHttp...}publicvoidonResponseSuccess(Responseresponse){RegisterViewOpsview=getView();if(view!=null){view.onRegisterSuccess();}}當(dāng)結(jié)果放回時(shí),Document便回調(diào)View組件的onRegisterSuccess()方法。通過使用我們所搭建的Document-View框架:這里我們不再需要自己顯式連接起Document和View組件不需要擔(dān)心由于配置改變引起的不必要的對(duì)象創(chuàng)建不會(huì)因?yàn)殄e(cuò)誤持有View引用而引發(fā)內(nèi)存泄露用戶界面與邏輯清晰分離使用框架的,幾乎不會(huì)產(chǎn)生什么重復(fù)的代碼5.2文件下載以模式語言的說法,,實(shí)現(xiàn)文件下載(文件上傳是類似的,這里便不再贅述)時(shí),需要平衡一下幾個(gè)作用力:文件下載屬于耗時(shí)較長(zhǎng)的操作,需要使用startedservice由于我們需要將下載進(jìn)度體現(xiàn)在UI上,需要使用boundservice網(wǎng)絡(luò)速度的不可預(yù)知的,我們需要將進(jìn)度“推”給View組件,而不能使用“拉”模型雖然Android的Service組件從語義上分為了startedservice和boundservice,并且有著各自不同的聲明周期,但是二者并不是互斥的。一個(gè)Service可以同時(shí)既是startedservice,也是boundservice。這正是我們所需要的。使用startedservice時(shí),我們需要在客戶的請(qǐng)求執(zhí)行后,調(diào)用stopSelf()結(jié)束自己。由于可能同時(shí)有多個(gè)下載任務(wù)在進(jìn)行,并且完成的順序是不確定的。我們需要一種機(jī)制,告訴我們,什么時(shí)候service應(yīng)該停止。這里我們使用一個(gè)集合來保存當(dāng)前正在下載的所有請(qǐng)求,文件下載完成時(shí),通過判斷集合是否為空,即可決定是否應(yīng)該停止自己。privatefinalObjectmLock=newObject();privatefinalSet<String>mDownloadingSet=newHashSet<>();publicvoidonResponseSuccess(Responseresponse){//...synchronized(mLock){mDownloadingSet.remove(mRemotePath);if(mDownloadingSet.isEmpty()){stopSelf();}}//...}由于網(wǎng)絡(luò)請(qǐng)求的回調(diào)是在后臺(tái)線程執(zhí)行的,并且可能同時(shí)有多個(gè)線程在執(zhí)行下載操作,我們需要對(duì)mDownloadingSet進(jìn)行同步處理。為了將鎖對(duì)象封裝起來,這里我們使用了一個(gè)私有的鎖對(duì)象而不是直接使用Service實(shí)例。與此同時(shí),我們將二者均聲明為final,以確保其內(nèi)存可見性。而對(duì)于操作的同步,則之間使用Java內(nèi)建的Monitor實(shí)現(xiàn)。為了將下載進(jìn)度發(fā)布至View組件,這里我們需要了觀察者模式。通過跟蹤當(dāng)前已下載的文件大小,我們可以得出下載的百分比。實(shí)現(xiàn)代碼見附錄E。6總結(jié)與展望6.1總結(jié)通過使用Document-View框架,整個(gè)應(yīng)用有著非常一致的結(jié)構(gòu),這對(duì)于應(yīng)用的維護(hù)和擴(kuò)展是至關(guān)重要的。并且,由于框架實(shí)現(xiàn)非常的輕量,整個(gè)框架所實(shí)現(xiàn)的功能都有著高效的利用率。經(jīng)過大量實(shí)踐驗(yàn)證的UI與邏輯分離的原則,使得應(yīng)用的實(shí)現(xiàn)非常的輕松,多數(shù)頁面甚至編碼后可以一次運(yùn)行便成功。但是,其實(shí)該框架實(shí)現(xiàn)也有著一些不足。由于Java的泛型實(shí)現(xiàn)需要向下兼容,引入了所謂的類型擦除。于是,當(dāng)我們實(shí)現(xiàn)GenericActivity時(shí),只得通過傳入一個(gè)Class<T>對(duì)象,并約定Document類的實(shí)現(xiàn)必須提供一個(gè)默認(rèn)構(gòu)造函數(shù)。雖然這保證了類型安全,但也就絕對(duì)談不上優(yōu)雅。再有一點(diǎn),雖然我們約定在GenericActivity的子類必須回調(diào)超類的onCreateDocument方法,以實(shí)例化Document對(duì)象,但是,就目前語言所提供的工具而已,我們并能夠在語言層級(jí)約束客戶必須調(diào)用該方法。事實(shí)上,在應(yīng)用編寫的過程中,我自己就曾有一次忘記調(diào)用該方法。好的設(shè)計(jì)總是有著一些折衷。為了類型安全和代碼的復(fù)用,我選擇了接受上述兩個(gè)缺點(diǎn)。6.2展望有些經(jīng)驗(yàn)豐富的開發(fā)人員將模式視為一種思維工具,他們建議首先考慮這樣的模式,即并非可直接用于開發(fā)的應(yīng)用程序的所屬領(lǐng)域。有時(shí)候,可將模式的重要理念推廣到另一個(gè)領(lǐng)域,進(jìn)而得到全新的模式或原有模式的變種。除了編程語言,程序員的效率還依賴于庫、框架和一系列的中間件。合適的模式能夠幫助程序員理解并高效地使用它們。隨著越來越多的開發(fā)人員人數(shù)認(rèn)識(shí)到模式的優(yōu)點(diǎn),有希望涌現(xiàn)這樣的一系列模式——它們都是軟件經(jīng)驗(yàn)的結(jié)晶。未來的框架文檔可能包含闡述如何有效使用框架的模式。參考文獻(xiàn)CayS.Horstmann,CaryCornel著,JAVA核心技術(shù)[M],卷一,卷二,第九版·英文版人民郵電出版社2013.07RetoMeier著,佘建偉、趙凱(譯),Android4高級(jí)編程[M](第3版)清華大學(xué)出版社2013.04.01JoshuaBloch著,楊春花、俞黎敏譯,EffectiveJava[M]中文版第2版機(jī)械工業(yè)出版社2009.01BrianGoetz,TimPeierls,JoshuaBloch,JosephBowbeer,DavidHolmes,DougLea著,童云蘭等譯,Java并發(fā)編程實(shí)戰(zhàn)[M],機(jī)械工業(yè)出版社2012.2ErichGamma,RichardHelm,RalphJohnson,JohnVlissides著,李英軍、馬曉星、蔡敏、劉建中等譯,設(shè)計(jì)模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ)[M],機(jī)械工業(yè)出版社2000.9CraigLarman著,李洋、鄭?等譯,UML和模式應(yīng)用[M]第三版,機(jī)械工業(yè)出版社2006.5任玉剛著,Android開發(fā)藝術(shù)探索[M],中國(guó)工信出版社,電子工業(yè)出版社2015FrankBuschmann,RegineMeunier,HansRohnert,PeterSommerlad,MichealStal著,Pattern-OrientedSoftwareArchitecture[M],Volume1–ASsytemofPatterns,JohnWiley&Sons,Ltd1996DouglasSchmidt,MichaelStal,HansRohnert,FrankBuschmann著,Pattern-OrientedSoftwareArchitecture[M],Volume2–PatternsforConcurrentandNetworkedObjects,JohnWiley&Sons,Ltd2000JamesGosling,BillJoy,GuySteele,GiladBrachaandAlexBuckley著,TheJavaLanguageSpecification[S],JavaSE8Edition.OracleAmerica,Inc.and/oritsaffiliates致謝本設(shè)計(jì)(論文)是在我的指導(dǎo)教師原玲副教授的親切關(guān)懷和悉心指導(dǎo)下完成的。他嚴(yán)肅的科學(xué)態(tài)度,嚴(yán)謹(jǐn)?shù)闹螌W(xué)精神,精益求精的工作作風(fēng),深深地感染和激勵(lì)著我。從題目的選擇到最終完成,原玲老師都始終給予我細(xì)心的指導(dǎo)和不懈的支持。附錄A一個(gè)簡(jiǎn)單的注冊(cè)頁面實(shí)現(xiàn)publicclassRegisterActivityextendsActivityimplementsView.OnClickListener{@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);//initview...}@OverridepublicvoidonClick(Viewv){//on"register"buttonclick//createanewthreadtoperformnetworkrequestnewThread(newRunnable(){@Overridepublicvoidrun(){//performnetworkrequest//andpublishresponsetotheUIthread}}).start();}}附錄BGenericActivitypublicabstractclassGenericActivity<ViewOps,DocumentOpsextendsBasicDocumentOps<ViewOps>>extendsAppCompatActivity{privateDocumentOpsmDocument;protectedvoidonCreateDocument(ViewOpsview,Class<?extendsDocumentOps>documentOpsClass){initDocument(documentOpsClass);
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2026年1月陜西漢中市中心醫(yī)院招聘導(dǎo)醫(yī)、超聲醫(yī)師、兒保康復(fù)教育師5人備考題庫(含答案詳解)
- 2026年甘肅蘭州皋蘭縣融媒體中心面向社會(huì)招聘主持人、全媒體記者備考題庫及答案詳解(易錯(cuò)題)
- 2026河南省老干部大學(xué)兼職教師招聘?jìng)淇碱}庫及參考答案詳解一套
- 2026廣東佛山市第二人民醫(yī)院招聘高層次人才(第一批)1人備考題庫及一套答案詳解
- 2025上海復(fù)旦大學(xué)外國(guó)留學(xué)生工作處招聘綜合科行政管理崗位1名備考題庫及1套參考答案詳解
- (2025年)建筑設(shè)備防火防爆專項(xiàng)習(xí)題(含答案)
- 2026北京市海淀區(qū)實(shí)驗(yàn)幼兒園招聘?jìng)淇碱}庫完整答案詳解
- 2025年放射科考試題庫及參考答案
- 2026四川綿陽長(zhǎng)虹國(guó)際酒店有限責(zé)任公司員工長(zhǎng)期招聘5人備考題庫及完整答案詳解一套
- 2025年《醫(yī)務(wù)人員職業(yè)防護(hù)》培訓(xùn)考試試題附答案
- 2025購房合同(一次性付款)
- 云南省茶葉出口競(jìng)爭(zhēng)力分析及提升對(duì)策研究
- 銀行情緒與壓力管理課件
- 甲狀腺危象護(hù)理查房要點(diǎn)
- 《無人機(jī)飛行安全及法律法規(guī)》第3版全套教學(xué)課件
- 2025內(nèi)蒙古電力集團(tuán)招聘筆試考試筆試歷年參考題庫附帶答案詳解
- 交通警察道路執(zhí)勤執(zhí)法培訓(xùn)課件
- 十五五學(xué)校五年發(fā)展規(guī)劃(2026-2030)
- 洗浴員工協(xié)議書
- GB/T 17642-2025土工合成材料非織造布復(fù)合土工膜
- 清欠歷史舊賬協(xié)議書
評(píng)論
0/150
提交評(píng)論