簡(jiǎn)稱(chēng):MVP 全稱(chēng):Model-View-Presenter 振诬;MVP 是從經(jīng)典的模式MVC演變而來(lái),它們的基本思想有相通的地方,Controller/Presenter負(fù)責(zé)邏輯的處理万细,Model提供數(shù)據(jù)辆沦,View負(fù)責(zé)顯示
模式特點(diǎn)
1.MVP是根據(jù)MVC演變而來(lái)
3.在MVC中友瘤,View是可以直接訪問(wèn)Model的权烧!從而眯亦,View里會(huì)包含Model信息,不可避免的會(huì)包括一些業(yè)務(wù)邏輯般码。 在MVC模型里妻率,更關(guān)注的Model的改變,而同時(shí)有多個(gè)對(duì)Model的不同顯示板祝,即View宫静。所以,在MVC模型里券时,Model不依賴(lài)于View孤里,但是View是依賴(lài)于Model的。不僅如此橘洞,因?yàn)橛幸恍I(yè)務(wù)邏輯在View里實(shí)現(xiàn)了捌袜,導(dǎo)致要更改View也是比較困難的,至少有些業(yè)務(wù)邏輯是無(wú)法重用的炸枣。
2.在MVP中 : View并不直接使用Model虏等,它們之間的通信是通過(guò)Presenter (也就是MVC中的Controller)來(lái)進(jìn)行的,所有的交互都發(fā)生在Presenter內(nèi)部适肠,而在MVC中View會(huì)直接從Model中讀取數(shù)據(jù)而不是通過(guò) Controller霍衫。
總結(jié):
雖然 MVC 中的 View可以訪問(wèn) Model,但是我們不建議在 View 中依賴(lài) Model侯养,而是要求盡可能把所有業(yè)務(wù)邏輯都放在 Controller 中處理敦跌,而 View只和 Controller 交互。
解決方式:
在MVP里逛揩,Presenter完全把Model和View進(jìn)行了分離柠傍,主要的程序邏輯在Presenter里實(shí)現(xiàn)。而且息尺,Presenter與具體的View是沒(méi)有直接關(guān)聯(lián)的携兵,而是通過(guò)定義好的接口進(jìn)行交互,從而使得在變更View時(shí)候可以保持Presenter的不變搂誉,即重用徐紧! 不僅如此,我們還可以編寫(xiě)測(cè)試用的View炭懊,模擬用戶(hù)的各種操作并级,從而實(shí)現(xiàn)對(duì)Presenter的測(cè)試--而不需要使用自動(dòng)化的測(cè)試工具。 我們甚至可以在Model和View都沒(méi)有完成時(shí)候侮腹,就可以通過(guò)編寫(xiě)Mock Object(即實(shí)現(xiàn)了Model和View的接口嘲碧,但沒(méi)有具體的內(nèi)容的)來(lái)測(cè)試Presenter的邏輯。 在MVP里父阻,應(yīng)用程序的邏輯主要在Presenter里實(shí)現(xiàn)愈涩,其中的View是很薄的一層望抽。因此就有人提出了Presenter First的設(shè)計(jì)模式,就是根據(jù)User Story來(lái)首先設(shè)計(jì)和開(kāi)發(fā)Presenter履婉。在這個(gè)過(guò)程中煤篙,View是很簡(jiǎn)單的,能夠把信息顯示清楚就可以了毁腿。在后面辑奈,根據(jù)需要再隨便更改View,而對(duì)Presenter沒(méi)有任何的影響了已烤。 如果要實(shí)現(xiàn)的UI比較復(fù)雜鸠窗,而且相關(guān)的顯示邏輯還跟Model有關(guān)系,就可以在View和Presenter之間放置一個(gè)Adapter胯究。由這個(gè) Adapter來(lái)訪問(wèn)Model和View稍计,避免兩者之間的關(guān)聯(lián)。而同時(shí)唐片,因?yàn)锳dapter實(shí)現(xiàn)了View的接口丙猬,從而可以保證與Presenter之間接口的不變。這樣就可以保證View和Presenter之間接口的簡(jiǎn)潔费韭,又不失去UI的靈活性茧球。 在MVP模式里,View只應(yīng)該有簡(jiǎn)單的Set/Get的方法星持,用戶(hù)輸入和設(shè)置界面顯示的內(nèi)容抢埋,除此就不應(yīng)該有更多的內(nèi)容,絕不容許直接訪問(wèn)Model,這就是與MVC很大的不同之處督暂。
優(yōu)點(diǎn):
1.分離了視圖邏輯和業(yè)務(wù)邏輯揪垄,降低了耦合
2.Activity 只處理生命周期的任務(wù),代碼變得更加簡(jiǎn)潔
3.視圖邏輯和業(yè)務(wù)邏輯分別抽象到了 View 和 Presenter 的接口中去逻翁,提高代碼的可閱讀性
4.Presenter 被抽象成接口饥努,可以有多種具體的實(shí)現(xiàn),所以方便進(jìn)行單元測(cè)試
5.把業(yè)務(wù)邏輯抽到 Presenter 中去八回,避免后臺(tái)線程引用著 Activity 導(dǎo)致 Activity 的資源無(wú)法被系統(tǒng)回收從而引起內(nèi)存泄露和 OOM
缺點(diǎn):
由于對(duì)視圖的渲染放在了Presenter中酷愧,所以視圖和Presenter的交互會(huì)過(guò)于頻繁。還有一點(diǎn)需要明白缠诅,如果Presenter過(guò)多地渲染了視圖溶浴,往往會(huì)使得它與特定的視圖的聯(lián)系過(guò)于緊密。一旦視圖需要變更管引,那么Presenter也需要變更了士败。比如說(shuō),原本用來(lái)呈現(xiàn)Html的Presenter現(xiàn)在也需要用于呈現(xiàn)Pdf了褥伴,那么視圖很有可能也需要變更谅将。
下面請(qǐng)看代碼實(shí)現(xiàn):
一漾狼、不使用MVP的代碼
下面開(kāi)始采用最簡(jiǎn)單的MVP模式來(lái)改造這個(gè)代碼:
1.創(chuàng)建一個(gè)類(lèi),用來(lái)封裝網(wǎng)絡(luò)請(qǐng)求(M層)
2.先定義一個(gè)接口,針對(duì)這個(gè)界面邏輯View需要作出的動(dòng)作戏自。
3.再創(chuàng)建一個(gè)類(lèi)邦投,用來(lái)處理M層和V層之間的通信,(P層)
4擅笔、讓Activity實(shí)現(xiàn)這個(gè)接口中的方法(V層)
上面這4步是最基本的MVP模式,但是這樣寫(xiě)會(huì)內(nèi)存泄漏,因?yàn)槿绻诰W(wǎng)絡(luò)請(qǐng)求的過(guò)程中Activity關(guān)閉了,Presenter還持有V層的引用.
解決:
在Presenter添加綁定和解綁方法,斷開(kāi)網(wǎng)絡(luò)方法:
修改后的activity:
這樣我們就解決了內(nèi)存泄露的問(wèn)題屯援,但是這樣還是不完美猛们,應(yīng)用中肯定不可能只有一個(gè)模塊,每個(gè)模塊都對(duì)應(yīng)著一個(gè)V層和P層狞洋,那這樣的話每個(gè)Presenter中都要定義綁定和解綁的方法弯淘,而Activity中對(duì)應(yīng)的也要調(diào)用這綁定和解綁的兩個(gè)方法,代碼冗余吉懊。
解決:
1.創(chuàng)建一個(gè)基類(lèi)View庐橙,讓所有View接口都必須實(shí)現(xiàn),用來(lái)約束類(lèi)型的
2.創(chuàng)建一個(gè)基類(lèi)Presenter,在類(lèi)上規(guī)定View泛型借嗽,然后定義綁定和解綁的抽象方法态鳖,讓子類(lèi)去實(shí)現(xiàn),對(duì)外在提供一個(gè)獲取View的方法恶导,
讓子類(lèi)直接通過(guò)方法來(lái)獲取View
3.創(chuàng)建一個(gè)基類(lèi)的Activity浆竭,聲明一個(gè)創(chuàng)建Presenter的抽象方法,因?yàn)橐獛妥宇?lèi)去綁定和解綁那么就需要拿到子類(lèi)的Presenter才行惨寿,但是又不能隨便一個(gè)類(lèi)都能綁定的邦泄,因?yàn)橹挥谢?lèi)的Presenter中才定義了綁定和解綁的方法,所以同樣的在類(lèi)上可以聲明泛型,在方法上使用泛型來(lái)達(dá)到目的裂垦。
4.修改Presenter和Activity中的代碼顺囊,各自繼承自己的基類(lèi)并去除重復(fù)代碼
待續(xù)!