倪紅軍
(南京師范大學(xué)泰州學(xué)院,江蘇泰州225300)
隨著移動互聯(lián)網(wǎng)技術(shù)和智能終端技術(shù)的發(fā)展,基于Android平臺的智能設(shè)備在人們的生活中越來越普及,運(yùn)行于Android平臺上的相應(yīng)軟件也越來越多,每個軟件承載的功能也是越來越強(qiáng),采用傳統(tǒng)的MVC(Model—View—Controller)開發(fā)模式開發(fā) 的Android平臺軟件,視圖層(View)一般采用XML文件進(jìn)行界面描述,控制層(Controller)的功能通常由Activity擔(dān)當(dāng),模型層(Model)用來實(shí)現(xiàn)對數(shù)據(jù)庫、網(wǎng)絡(luò)及業(yè)務(wù)計(jì)算等的操作。雖然MVC模式將界面呈現(xiàn)和邏輯代碼分離開了,但View對應(yīng)的XML文件實(shí)際能實(shí)現(xiàn)的功能很少,很多界面呈現(xiàn)都必須由Controller對應(yīng)的Activity完成,這樣Activity既充當(dāng)了View的角色,又充當(dāng)了Controller的角色。隨著用戶界面及其業(yè)務(wù)邏輯的復(fù)雜度不斷提升,Activity的職責(zé)也會不斷增加,使得Activity越來越龐大臃腫和耦合度越來越高,從而導(dǎo)致項(xiàng)目的后期維護(hù)變得越來越復(fù)雜[1-3],對于開發(fā)周期比較短的小型項(xiàng)目這種模式是可以接受的,但如果開發(fā)一個界面和業(yè)務(wù)邏輯復(fù)雜度都很高的項(xiàng)目來說,這種開發(fā)模式耦合度高、維護(hù)困難等問題就突顯出來了。綜上所述,傳統(tǒng)的MVC開發(fā)模式并不很適合運(yùn)用于Android平臺軟件的開發(fā)。
針對以上問題,在進(jìn)行Android平臺軟件開發(fā)時(shí),需要探索另外一種更適合的開發(fā)模式進(jìn)行Android平臺軟件的開發(fā),以便將復(fù)雜的業(yè)務(wù)邏輯進(jìn)行分解處理,讓Activity的職責(zé)更加單一、代碼耦合度更低、軟件結(jié)構(gòu)層次更加清晰,以提高代碼的靈活性和可維護(hù)性。經(jīng)過研究和實(shí)踐發(fā)現(xiàn)MVP模式能夠很好的解決這類問題。本文通過對MVP開發(fā)模式的研究分析,探討Android應(yīng)用開發(fā)中使用MVP開發(fā)模式的原因,并結(jié)合基于Web Service的教師任課信息管理系統(tǒng)的登錄模塊實(shí)現(xiàn)過程,探討Android應(yīng)用開發(fā)中使用MVP開發(fā)模式的軟件設(shè)計(jì)流程。
MVP(Model-View-Presenter)模式是 2000年左右由IBM開發(fā)出來的一個針對C++和Java的編程模型,是 MVC(Model-View-Controller)模式演變而來的,在應(yīng)用開發(fā)中它們具有基本相通的設(shè)計(jì)思想:Controller/Presenter負(fù)責(zé)邏輯的處理,Model提供數(shù)據(jù),View負(fù)責(zé)顯示。MVC的設(shè)計(jì)模型圖如圖1所示,MVP的設(shè)計(jì)模型圖如圖2所示。
圖1 MVC設(shè)計(jì)模式
圖2 MVP設(shè)計(jì)模式
在MVC設(shè)計(jì)模式中,Model是應(yīng)用程序中用于處理業(yè)務(wù)邏輯的部分,通常負(fù)責(zé)定義數(shù)據(jù)修改和操作的業(yè)務(wù)規(guī)則;View是應(yīng)用程序處理數(shù)據(jù)顯示的部分,通常負(fù)責(zé)展示依據(jù)Model創(chuàng)建的數(shù)據(jù);Controller是應(yīng)用程序中處理用戶交互的部分,通常負(fù)責(zé)處理流入的請求[4-6]。當(dāng)View接收用戶的輸入后,可以通過Controller修改對應(yīng)的Model實(shí)例數(shù)據(jù),也可以由View層直接更新Model數(shù)據(jù)[7-10];當(dāng)Model的數(shù)據(jù)發(fā)生變化并需要修改用戶界面時(shí),可以通過Controller實(shí)現(xiàn)。
從圖1可以看出,在MVC模式中View是可以直接訪問Model的,所以View中也會包含Model信息和一些業(yè)務(wù)邏輯。Model不依賴于View,但View是依賴于Model的。由于一些業(yè)務(wù)邏輯在View里實(shí)現(xiàn),從而導(dǎo)致View的更改比較困難,業(yè)務(wù)邏輯也無法重用。
在MVP設(shè)計(jì)模式中,Model和View的主要功能與MVC設(shè)計(jì)模式基本相同,Presenter是Model與View之間的橋梁,它從Model獲得數(shù)據(jù)后,返回給View,使得View與Model之間沒有耦合,也將業(yè)務(wù)邏輯從View中抽離出來。
從圖2可以看出,在MVP模式中Presenter完全把Model和View進(jìn)行了分離,主要的程序邏輯在Presenter里實(shí)現(xiàn)。而且,Presenter與具體的View是沒有直接關(guān)聯(lián)的,而是通過定義好的接口進(jìn)行交互,從而使得在變更View時(shí)可以保持Presenter不變。這樣的分層模式大大降低了Model層與View層的耦合度,一方面可以實(shí)現(xiàn)View層和Model層的單獨(dú)開發(fā)與測試,互不依賴;另一方面有利于Model層的封裝復(fù)用,大大減少了代碼量[11-12]。
在Android應(yīng)用開發(fā)中使用MVP模式,將Model層和View層通過Presenter層實(shí)現(xiàn)完全分分離,主要的業(yè)務(wù)邏輯在Presenter層中實(shí)現(xiàn)。Presenter層持有View層和Model層的Interface(接口)引用,View層持有Presenter層的Interface(接口)引用。當(dāng)View層的某個用戶界面(UI)需要展示數(shù)據(jù)時(shí),首先調(diào)用Presenter層的相關(guān)Interface,然后Prensenter層調(diào)用Model層請求數(shù)據(jù),當(dāng)Model層數(shù)據(jù)加載成功后,調(diào)用Presenter層的CallBack(回調(diào)方法)通知Presenter層數(shù)據(jù)加載完畢,最后Presenter層調(diào)用View層的Interface將加載后的數(shù)據(jù)在用戶界面展示。
使用MVP模式進(jìn)行Android應(yīng)用開發(fā)時(shí),MVP模式主要包含4個關(guān)鍵部分:
1)View:由 Activity類或 Fragment類實(shí)現(xiàn),負(fù)責(zé)與用戶的交互及視圖部分展示;
2)View interface:需要View實(shí)現(xiàn)的接口,其中定義了View行為的抽象,View通過該接口與Presenter進(jìn)行交互,使用該接口主要為降低程序間的耦合度;
3)Model:負(fù)責(zé)存儲、訪問數(shù)據(jù)的實(shí)體類,數(shù)據(jù)可以是遠(yuǎn)端的Server API、本地?cái)?shù)據(jù)庫或SharedPrefer?ences等;
4)Presenter:負(fù)責(zé)完成View與Model間交互的業(yè)務(wù)邏輯類,一個Presenter可以對應(yīng)多個View。
下面就以基于Web Service的教師任課信息管理系統(tǒng)的登錄模塊為例介紹MVP模式在Android應(yīng)用開發(fā)中的實(shí)現(xiàn)過程。登錄模塊包括Web Service服務(wù)器端和Android客戶端兩個部分。
服務(wù)器端是基于ASP.Net平臺創(chuàng)建的Web Service,向開發(fā)者提供調(diào)用接口如圖3所示。其中username表示登錄用戶的用戶名,password表示登錄用戶的密碼。如果登錄用戶是管理員,返回“1”;如果登錄用戶是普通教師,返回“2”;否則返回“3”。Web Service的實(shí)現(xiàn)技術(shù)不是本文研究內(nèi)容,所以不作詳述。
圖3 Web Service調(diào)用接口
圖4 客戶端目錄結(jié)構(gòu)
客戶端使用MVP模式實(shí)現(xiàn),實(shí)現(xiàn)的目錄結(jié)構(gòu)如圖4所示。
登錄模塊的Model層主要負(fù)責(zé)從Web Service服務(wù)器獲取登錄信息,由ITeacher和LoginOnListener兩個接口類及一個TeacherImpl實(shí)現(xiàn)類組成。
1)ITeacher和LoginOnListener接口類
ITeacher接口定義了需要實(shí)現(xiàn)的login方法,其關(guān)鍵代碼如下:
LoginOnListener接口定義了登錄后需要處理的adminSuccess()、teacherSuccess()和loginFailed()方法,分別表示管理登錄成功、老師登錄成功和登錄失敗。
2)TeacherImpl實(shí)現(xiàn)類
由于從Web Service服務(wù)器獲取登錄信息是一個耗時(shí)操作,所以需要使用線程實(shí)現(xiàn)[13-17]。其中LinkWeb是自定義的一個訪問Web Service的工具類,關(guān)鍵代碼如下:
View層登錄模塊展示的組件是AppCompatAc?tivity,其布局文件使用嵌套的RelativeLayout布局,運(yùn)行后的效果如圖5所示。為了方便Presenter與View的交互,View層定義了一個ITeacherLoginView接口類,該接口中包含了登錄成功頁面跳轉(zhuǎn)方法、加載過程中給用戶信息提示方法、從登錄界面獲取用戶名和密碼的方法,其關(guān)鍵代碼如下:
圖5 登錄界面
在登錄界面AppCompatActivity中實(shí)現(xiàn)ITeacher?LoginView 接口,并重寫 toFirstActivity()、showToast(String msg)、getUsername()及 getPassword()方法,以實(shí)現(xiàn)相關(guān)功能。
View層需要調(diào)用Presenter層訪問Model層的信息,所以在Presenter層定義了一個實(shí)現(xiàn)LoginOnLis?tener接口的LoginPresenter類,其中包含一個需要傳入View層的接口對象iTeacherLoginView、一個用于訪問Model層的信息的login方法及LoginOnListener接口中需要重寫的方法,其關(guān)鍵代碼如下:
當(dāng)用戶在LoginActivity界面單擊Button后,Logi?nActivity會調(diào)用 LoginPresenter的 login方法,Login?Presenter的login方法中又會調(diào)用ITeacher中的login方法。ITeacher中的login方法是加載數(shù)據(jù)的核心,通過自定義的LinkWeb工具類中的connectService?ForLogin方法請求Web Service服務(wù)器接口獲取數(shù)據(jù),并通過LoginOnListener接口回調(diào)給LoginPresenter。
文中通過對Android應(yīng)用開發(fā)中使用MVC模式實(shí)現(xiàn)過程進(jìn)行分析,發(fā)現(xiàn)了MVC模式中充當(dāng)View層功能的xml文件控制能力較弱,諸如動態(tài)隱藏/顯示按鈕等功能在xml中根本沒有辦法實(shí)現(xiàn),只能將實(shí)現(xiàn)代碼寫到Activity中,造成了Activity在MVC模式中既充當(dāng)了Controller,又充當(dāng)了View,從而導(dǎo)致Activity臃腫不堪、業(yè)務(wù)邏輯耦合度高及項(xiàng)目后期維護(hù)難度大等問題。
根據(jù)MVP模式的設(shè)計(jì)思想,Android應(yīng)用開發(fā)中的Model與MVC模式中一樣,而Activity不再是Controller的角色,而純粹是View的角色,所有的業(yè)務(wù)事件統(tǒng)一由Presenter負(fù)責(zé)處理,Model和View完全解耦,從而使Android平臺的應(yīng)用開發(fā)模塊職責(zé)劃分明顯、代碼復(fù)用度高和靈活性強(qiáng),便于項(xiàng)目的后期維護(hù)和功能擴(kuò)展。為了驗(yàn)證MVP模式在Android應(yīng)用開發(fā)中的可行性,最后基于MVP模式設(shè)計(jì)并實(shí)現(xiàn)了教師任課信息管理系統(tǒng)登錄模塊,達(dá)到了預(yù)期效果。