在構(gòu)建iOS
應(yīng)用程序時(shí)虎囚,測試并不總是我們的主要工作。而當(dāng)我們在移動(dòng)開發(fā)中想要豐富測試經(jīng)驗(yàn)時(shí)赵讯,我們發(fā)現(xiàn)給iOS
應(yīng)用寫測試代碼有一定困難——即使我們遵循了Apple
的指導(dǎo)原則并且實(shí)現(xiàn)了其 MVC
模式巡揍。為了更好地測試我們必須想辦法用更好的方式去構(gòu)建我們的iOS
應(yīng)用程序。那么個(gè)好的架構(gòu)應(yīng)該具備哪些特點(diǎn)呢油够?
1.各個(gè)實(shí)體分工明確蚁袭,任務(wù)量分配適中
2.可測試性(當(dāng)然做好第一點(diǎn),第二點(diǎn)往往就具備了)
3.易用性和低成本維護(hù)
既然我們定義了好的架構(gòu)模式的特點(diǎn)石咬,下面我們來一一回顧一下那些常用的架構(gòu)模式是否符合我們理想的iOS
應(yīng)用程序構(gòu)建模式揩悄。
MVC模式:
MVC
即Model-VIew-Controller
。MVC
模式致力于關(guān)注點(diǎn)的切分鬼悠,這意味著model
和controller
的邏輯是不與用戶界面(View
)掛鉤的删性。Model
層代表了描述業(yè)務(wù)邏輯和數(shù)據(jù)的一系列類的集合。它也定義了數(shù)據(jù)修改和操作的業(yè)務(wù)規(guī)則焕窝。View代
表了UI
組件蹬挺,像UIView
,UIButton
袜啃,UITableView
等汗侵。他只負(fù)責(zé)展示從controller
接收到的數(shù)據(jù)。因此群发,維護(hù)和測試程序變得更加簡單容易晰韵。然而在Cocoa
的MVC
模式中Controller
經(jīng)常被混雜在View的生命周期中,因此很難說View
和ViewController
是分離的熟妓,這也往往驅(qū)使人們寫出臃腫的視圖控制器雪猪,盡管仍可以將業(yè)務(wù)邏輯和數(shù)據(jù)轉(zhuǎn)換到Model
,但是大多數(shù)情況下當(dāng)需要為View
減負(fù)的時(shí)候我們卻無能為力了起愈。View
的最大的任務(wù)就是向Controller
傳遞用戶動(dòng)作事件只恨。ViewController
不再承擔(dān)一切代理和數(shù)據(jù)源的職責(zé)译仗,通常只負(fù)責(zé)一些分發(fā)和取消網(wǎng)絡(luò)請求以及一些其他的任務(wù)。當(dāng)在進(jìn)行單元測試的時(shí)候你會(huì)發(fā)現(xiàn)問題越來越明顯官觅。因?yàn)槟愕?code>ViewController和View
是緊密耦合的纵菌,對它們進(jìn)行測試就顯得很艱難。Cocoa MVC
看來并不是我們定義中理想的架構(gòu)模式休涤。MVP模式:這個(gè)模式把
Presenter
換成Controller
就和MVC
非常相像了咱圆。這個(gè)設(shè)計(jì)模式把應(yīng)用程序分成了3個(gè)主要方面:Model
、View
和Presenter
,其中的Model
和View
與MVC模中的角色相同功氨。Presenter
負(fù)責(zé)處理View
背后所有的UI事件序苏。它通過View
接收用戶輸入,之后利用Model
來處理用戶的數(shù)據(jù)捷凄,最后把結(jié)果返回給View
忱详。與View
和Controller
不同,View
和Presenter
之間是完全解耦的跺涤,他們通過接口來交互匈睁。另外,presenter
不像controller
處理進(jìn)入的請求钦铁。這不是正解決了Cocoa MVC
中ViewController
和View
的耦合問題嗎软舌?就MVP模式而言,UIViewController
的子類實(shí)際上就是Views
并不是Presenters
牛曹。這點(diǎn)區(qū)別使得這種模式的可測試性得到了極大的提高佛点,付出的代價(jià)是開發(fā)速度的一些降低,因?yàn)楸仨氁鲆恍┦謩?dòng)的數(shù)據(jù)和事件綁定黎比。但是這也意味著我們將最主要的任務(wù)劃分到Presenter
和Model
超营,而View
的功能較少——各個(gè)實(shí)體任務(wù)量分配不均衡。MVVM模式:即
Model-View-View Model
阅虫。這個(gè)模式提供對View
和View Model
的雙向數(shù)據(jù)綁定演闭。這使得View Model
的狀態(tài)改變可以自動(dòng)傳遞給View
。典型的情況是颓帝,View Model
通過使用obsever
模式(觀察者模式)來將View Model
的變化通知給model
米碰。View Model
負(fù)責(zé)暴漏方法,命令购城,其他屬性來操作VIew
的狀態(tài)吕座,組裝model
作為View
動(dòng)作的結(jié)果,并且觸發(fā)View
自己的事件瘪板。它和MVP模式看起來非常像:MVVM
將ViewController
視作View
,View
和Model
之間沒有緊密的聯(lián)系吴趴。在使用MVVM模式時(shí),自然而然會(huì)想到ReactiveCoca
侮攀,反之亦然锣枝。盡管通過簡單的綁定來使用MVVM
是可實(shí)現(xiàn)的厢拭,但是ReactiveCocoa
卻能更好的發(fā)揮MVVM模式的特點(diǎn)。但是使用這個(gè)框架有個(gè)難以忽略的事實(shí):當(dāng)你剛開始使用ReactiveCoca
的時(shí)候有很大的可能就會(huì)把事情搞砸撇叁。換句話來說就是供鸠,如果發(fā)現(xiàn)了一些錯(cuò)誤,當(dāng)你試圖查看函數(shù)調(diào)用棧時(shí)你可能會(huì)喊:“天哪陨闹,好深的函數(shù)調(diào)用椈丶荆“!調(diào)試出這個(gè)bug可能會(huì)花費(fèi)大量的時(shí)間正林。MVVM很誘人,因?yàn)樗狭松鲜龇椒ǖ膬?yōu)點(diǎn)颤殴,并且由于在View層的綁定觅廓,它并不需要其他附加的代碼來更新View,盡管這樣涵但,可測試性依然很強(qiáng)——符合我們理想中好架構(gòu)模式的定義杈绸。Viper架構(gòu)模式:由視圖 (View),交互器 (Interactor)矮瘟,展示器 (Presenter)瞳脓,實(shí)體 (Entity) 以及路由 (Routing) 組成。
視圖:根據(jù)展示器的要求顯示界面澈侠,并將用戶輸入反饋給展示器劫侧。
交互器:包含由用例指定的業(yè)務(wù)邏輯。
展示器:包含為顯示(從交互器接受的內(nèi)容)做的準(zhǔn)備工作的相關(guān)視圖邏輯哨啃,并對用戶輸入進(jìn)行反饋(從交互器獲取新數(shù)據(jù))烧栋。
實(shí)體:包含交互器要使用的基本模型對象。
路由:包含用來描述屏幕顯示和顯示順序的導(dǎo)航邏輯拳球。
Viper將應(yīng)用程序的邏輯結(jié)構(gòu)劃分為不同的責(zé)任層审姓。這使得它更容易隔離依賴項(xiàng) (如數(shù)據(jù)庫),也更容易測試各層間的邊界處的交互祝峻。
Viper的不同層提供了明確的程序邏輯以及導(dǎo)航控制代碼來避免視圖控制器太過于臃腫的問題魔吐,利用 Viper ,視圖控制器可以簡潔高效莱找,意義明確地控制視圖酬姆。視圖控制器中代碼和所有的其他類很容易理解,容易測試宋距,理所當(dāng)然也更易維護(hù)轴踱。
毫無疑問,Viper在劃分責(zé)任的粒度上比以上幾種模式都要優(yōu)秀谚赎,自然而然就有更好的可測試性淫僻,當(dāng)然你必須為很小功能的類寫出大量的接口诱篷。如果是在大型項(xiàng)目中使用Viper,Viper架構(gòu)模式符合我們理想中好架構(gòu)模式的定義雳灵。
從以上幾種架構(gòu)模式的分析中我們可以知道:沒有哪種架構(gòu)模式是絕對好的棕所,所以選擇架構(gòu)模式是一個(gè)根據(jù)實(shí)際情況具體分析利弊的過程。