20161002 MVC與MVVM
MVC
這算是一種開發者都很熟悉的開發架構,三種簡寫分別是模型 (model)- 視圖(view)-控制器 (controller)的縮寫,是這幾年來很流行的一種設計模式。
最早是xeror全錄實驗室為了Smalltalk語言發明出來的,學過Objective-C語言的應該都知道,他是來自於Smalltalk,因此也有了MVC的特性。
在 iOS 開發,整個藍圖已經佈局好視圖類別:UIView,控制器類別:UIViewController,因為蘋果官方已經把IDE設計成容易符合MVC架構的寫作方式,因此很難有辦法逃離這種架構。
但最大的問題是,MVC受到控制器影響,容易把控制器越寫越大。
MVC最大的精神是為了要符合物件導向設計,低耦合(coupling),高內聚(cohesion)的特色。
物件導向的精神就是增加重複使用的特性。
針對視圖層(view)而言,如果抽象化做的夠好,可以很容易移植到其他的App上,開源程式碼都必須做到可以讓其他人使用起來非常的方便與有彈性。
模型層(model),主要的功能是用來儲存數據,但因為涉及到了數據,所以無法開源使用。
MVC最大的精神是為了要符合物件導向設計,低耦合(coupling),高內聚(cohesion)的特色。
物件導向的精神就是增加重複使用的特性。
針對視圖層(view)而言,如果抽象化做的夠好,可以很容易移植到其他的App上,開源程式碼都必須做到可以讓其他人使用起來非常的方便與有彈性。
模型層(model),主要的功能是用來儲存數據,但因為涉及到了數據,所以無法開源使用。
控制器(controller)來說可以利用addSubViewController
的類別方式重複使用 Controller,但這類的使用比例上還是很少。所以怎樣的程式碼應該寫在Controller 裡面?那就是無法重複被使用的程式碼。
包括以下幾項
1.在初始化時,對應的View和Model
2.監聽Model的事件,將Model轉到View
3.監聽View的事件,將View轉到Model
如果 Controller 只有以上的這些程式碼,將會變讓程式碼瘦身變得非常確實,但新手還是常常會把程式碼寫進ViewController裡面。
幫 ViewController 減肥?
以下這篇文章就明確的對這件事情做詳細的介紹
https://www.objc.io/issues/1-view-controllers/lighter-view-controllers/
- UITableView 當中 Data Source 拆成到另外一個類別。
- 將Getter數據和轉換拆成一個類別。
- 將組裝起來的程式碼也拆成另外一個獨立的類別。
雖然MVC的設計模式只有三層,但實際的類別不一定只有三個。
網路請求獨立成一個單一的類別
新手寫程式碼,直接就在 Controller 裡面用 AFNetworking 發一個Request,Request完成直接發給 View。進階一點的會把這些Request轉移到另外一個靜態類別。,
但正確的做法應該是將每一個網路Request的動作都封裝成一個類別。
把每一個網路Request封裝成物件其實使用了Command模式:
但正確的做法應該是將每一個網路Request的動作都封裝成一個類別。
把每一個網路Request封裝成物件其實使用了Command模式:
- 將Request實際上與第三方隔離,以後可以很簡單的抽換底層網路的架構。比如 ASIHttpRequest 苦可以輕鬆切換到 AFNetworking。
- 在基礎類別可以處裡Public的演算法。
- 在基礎類別處理緩存的演算法。
- 物件的Persistence比較好處理。
可以參考中國所攥寫的YTKNetwork。可以支持Request managment,續傳,plugin,JSON 語法檢查等功能。
將interface的拼裝抽象到專門的類別中
新手寫程式碼, Controller 中把 UILabel ,UIButton,UITextField 往
有兩種方法可以擺脫這種方式
self.view
上用 addSubView
方法放。有兩種方法可以擺脫這種方式
方法一:建造專門 UIView 的子類別,来負責拼装。這是最徹底與優雅的方式,不過稍微麻煩一些的是,你需要把事件都接管,再都一一暴露回 Controller。
方法二:用一個靜態的 Util 类,幫你做 UIView 的拼装工作。這種方式稍微做得不太徹底,但是比較簡單。
對於一些能重複使用的 UI 控件,我建議用方法一。如果比較複雜,也建議用方法一,如果程式碼數量不多可以選擇方法二。
建構 ViewModel
誰說 MVC 就不能用 ViewModel 的?MVVM 的優點我们一樣可以借鏡。具体做法就是將ViewController 给 View 傳遞數據這個過程,抽象成構造 ViewModel 的過程。
這樣抽象之後,View 只接受 ViewModel,而 Controller 只需要傳遞 ViewModel 這麼一行程式碼。而另外建造 ViewModel 就可以移到另外的類別當中。
專門建造 ViewModel 工廠類鼻,可以看一下工廠模式。也可以特別將數據存取都抽到一個Service層,由這層來提供ViewModel的獲取。
專門建構儲存類別
ViewModel 的構造可以抽到Service 層。對應到,數據儲存也應該由專門的物件來做。
數據儲存放在專門的類別,針對存取做額外的事情
比如:
對熱點數據增加緩存
處理數據遷移相關的方法
如果要做得更细,可以把儲存引擎再抽象出一層。這樣就可以方便切換儲存的底層,例如從 sqlite 切换到 key-value 的儲存引擎等。
比如:
對熱點數據增加緩存
處理數據遷移相關的方法
如果要做得更细,可以把儲存引擎再抽象出一層。這樣就可以方便切換儲存的底層,例如從 sqlite 切换到 key-value 的儲存引擎等。
結論
透過程式碼抽取,將原本 MVC 設計模式中的 ViewController 進一步拆解,建構出 網路Request層、ViewModel 層、Service 層、Storage 層等其它類別,来配合 Controller 工作,來使得 Controller 更加簡單,使得APP好維護。
另外,不知道大家注意到没,其實 Controller 層是很難進行測試,如果我們能夠將 Controller 減肥,就可以更方便地寫 Unit Test 来測試各種與介面無關的方法。手機自動化测试框架都不太成熟,但是將 Controller 的程式碼抽取出來,有助於做測試工作。
MVVM
MVVM是 Model-View-ViewModel 的简写。
MVVM 算是一個新的架構,MVVM 最早是 2005 年被微軟的 WPF 和 Silverlight 的架構師John Gossman 提出,並且應用在微軟的設計模式。 MVC已经被提出了 20 多年了,兩者相比MVVM新很多。
MVVM 通常還會利用雙向綁定技術,使得 Model變化时,ViewModel 會自動更新,而 ViewModel 變化时,View 也會自動變化。所以,MVVM 模式也被稱作:model-view-binder 模式。
具体在 iOS 中,可以使用 KVO 或 Notification 技術達到這種效果。
MVVM 的誇大
在使用中, MVVM 以及 MVVM 衍生出来的框架(比如 ReactiveCocoa),ReactiveCocoa 本身上手的複雜性,讓很多人感覺到這種技術高深莫測。
MVVM 的作用和问题
MVVM 在實際使用上,確實能夠讓 Model 层和 View 層解除coupling,但是如果需要實現 MVVM 中的雙向綁定的话,就要引入更多複雜的項目來實現。
對此,MVVM 的作者 John Gossman 的 批評 是最為中肯。John Gossman 對 MVVM 的批評主要有兩點:
第一點:數據綁定使得 Bug 很難被測試。你看到介面異常,可能是 View 的程式碼有 Bug,也可能是 Model 的程式碼有問題。數據綁定使得一個位置的 Bug 被快速傳遞到别的位置,要定位原始出問題的地方不是那麼容易。
第二點:對於過大的專案,數據綁定需要花費更多記憶體空間。
就某種意義上,數據綁定使得 MVVM 變得複雜和難用了,但是這個缺點也被很多人認為是優點。
ReactiveCocoa
函数式程式設計(Functional Programming)和響應式程式設計(React Programming)也是可以很容易實現數據綁定。在iOS程式設計中,ReactiveCocoa 横空出世了,它的概念都非常 新,包括:
- 函数式程式設計(Functional Programming),函数也變成一等公民了,可以擁有和物件一樣的功能,例如當成參數傳遞,當作回傳值。看看 Swift 语言带来的許多函数式程式設計的特性,就你知道这多潮了。
- 響應式程式設計(React Programming),原來基於(Event)的處理方式都弱了,基於輸入(在 ReactiveCocoa 裡叫 Signal)的處理方式。輸入可以通過函数式程式設計進行各種 Combine 或 Filter,盡顯各種靈活的處理。
- 無狀態(Stateless),狀態是函数的魔鬼,無狀態使得函数能更好地測試。
- 不可修改(Immutable),數據都是不可修改的,使得軟體使用簡單,更好測試。
MVVM 和 ReactiveCocoa
但我們好像只需要一個 ViewModel 而已,可以簡單做一個 ViewModel 的工廠或 Service 類別就可以了,為什麼要引入這麼多框架?現有的MVC有這麼大的問題媽?
直到現在,ReactiveCocoa 在國內外都是在小眾,没有被大量接受成為主流。不只是在 iOS 言,在别的語言中,例如 Java 中的 RxJava 也同樣沒有成為主流。
ReactiveCocoa,同樣造成Controller 程式碼過於複雜,不易維護的問題。
總結
過於追求新技術,不評估新技術帶來的缺點與過於守舊,守著就技術都是不好的。
應該去觀察新技術的優美,以及了解舊技術可以用哪些方式改寫依舊具有好維護測試的特性。
0 意見