你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> MVVM奇葩說

MVVM奇葩說

編輯:IOS開發基礎

20160411014921837600.jpg

投稿文章,作者:龐海礁(微博、Github)

一直想聊聊這個話題,也有朋友跟我留言,讓我講講MVVM,只可惜一直沒整明白,不敢輕易下筆。針對MVVM,網上有很多不錯的文章,比如MVVM介紹、被誤解的 MVC 和被神化的 MVVM以及Look at MVVM from a different perspective等等。

文章前我想先提幾個問題:

  • MVVM到底是什麼?它和MVC有什麼區別?

  • MVVM中VM到底是個什麼角色?它和Controller或者Manager有什麼區別?

  • ViewController在MVVM中扮演怎樣角色?Api數據請求放在哪裡?數據流向如何?

MVVM簡介

關於MVVM,相信大家或多或少都有了解。引用MVVM介紹文中一圖:

mvvm.png

受MVC或MVP架構的影響,對MVVM最初印象以為這是一個以ViewModel為核心,處理View和Model的開發架構。於是乎在原有MVC的基礎上,創建了一個所謂的ViewModel對象,然後把ViewController中的代碼移到ViewModel中,在ViewModel裡面處理View以及Model的所有邏輯。畢竟大家都在說MVVM可以為ViewController瘦身,這ViewController就剩創建ViewModel的代碼,嗯,夠瘦身,這就是MVVM!

慢慢的,發現有什麼地方不對,哪裡不對?第一想法就是ViewController的定位,View?不是,Controller?也不是!畢竟它就創建ViewModel,好像與View、Model也沒啥關系。拋開ViewController不談,突然發現這樣的ViewModel、Model以及View不就是MVC,一個以ViewModel為中心的MVC!

1463642020697989.jpg

錯在哪裡

核心問題就在於對ViewModel角色的定位不清!基於MVVM設計思路,ViewModel存在目的在於抽離ViewController中展示業務邏輯,而不是替代ViewController,其它視圖操作業務等還是應該放在ViewController中實現。

既然不負責視圖操作邏輯,ViewModel中就不應該存在任何View對象,更不應該存在Push/Present等視圖跳轉邏輯。因此,ViewModel中絕不應該存在任何視圖操作相關的代碼

@interface ViewModel : NSObject
// viewmodel中切不可存在view對象,更不該出現push或者present代碼
- (instancetype)initWithTableView:(UITableView *)tableView;
@end

ViewModel做啥

很簡單,處理視圖展示邏輯,ViewModel負責將數據業務層提供的數據轉化為界面展示所需的VO。其與View一一對應,沒有View就沒有ViewModel

比如,數據業務層傳遞一個含有性別屬性sex的DO對象,0表示男, 1表示女。ViewModel的職責就是將其轉化為展示層可顯示的VO對象

self.personVO.sex = personDO.sex == 0 ? @"男": @"女";

ViewModel和View一起組成DDD(Model-Driven Design)領域驅動架構體系中的Presentation展示層。在iOS中,數據流向可以表示為ViewModel->ViewController->View,ViewController負責連接VO及其對應的View對象

領域驅動設計

領域驅動設計(DDD)對於安卓童鞋可能非常熟悉,有興趣的童鞋可以參考這篇文章,本文不做過多講解,借用其描述介紹幾個名詞

  • VO(View Object):視圖對象,用於展示層,它的作用是把某個指定頁面(或組件)的所有數據封裝起來

  • DO(Domain Object):領域對象,就是從現實世界中抽象出來的有形或無形的業務實體

  • PO(Persistent Object):持久化對象,它跟持久層(通常是關系型數據庫)的數據結構形成一一對應的映射關系,如果持久層是關系型數據庫,那麼,數據表中的每個字段(或若干個)就對應PO的一個(或若干個)屬性

  • Domain:領域驅動層,是用戶與數據庫交互的核心中轉站,控制用戶數據收集,控制請求轉向等

MVVM架構中,ViewModel連接視圖View和數據業務Model層,而Domain和Data數據持久層共同組成整個Model層。完整結構如圖所示:

mvvm-(1).jpg

Model並不表示Model

MVVM架構中的M,並不表示Model對象,而是表示整個數據業務層,對應DDD架構中的Domain層以及數據Data層。業務開發中,一般考慮Api或者DB對象,極少考慮Domain層設計,也不會區分DO或者PO對象。籠統定義Model ,將其傳遞給展示層ViewModel,久而久之,Model對象承載的信息越來越多,更有甚者,在Model中處理業務邏輯,導致項目維護成本增加,代碼中出現if..else的概率也會越來越大:

@interface PersonModel : NSObject
@property (nonatomic, assign) NSInteger sex;
@property (nonatomic, readonly) NSString *sexDescription;
@end
@implementation PersonModel
// model中不應該存在業務邏輯代碼
- (NSString *)sexDescription {
    return self.sex == 0 ? @"男": @"女";
}
@end

當然,Domain層並不是必須的,實際開發中,需要根據具體復雜度和需求來決定。比如只是純粹的請求展示界面,設計過多的層次結構反而會增加項目的維護成本。同時,Domain層不應該存在任何狀態變量!

Data數據層

ViewModel負責展示層邏輯,而Data層則對應數據層邏輯,一般以Manager或者Service身份存在,數據來源主要包括Api、DB或者Cache等。Data數據層操作對象主要為PO持久化對象,對象一旦創建,原則上不可修改

Data數據層具有獨立可測試性,其不依賴視圖層而存在。切記不可在Data層操作任何視圖對象!

@implementation PersonDBAccess
// Data層不應該存在任何視圖相關代碼
- (NSArray *)fetchPersonModels {
    [SVProgressHUD showWithStatus:@"加載中。。。"];
}
@end

MVVM奇葩說

文章到此,想必各位對MVVM架構已經有了大致了解。對比安卓童鞋對MVP架構的鐘愛,iOS童鞋也許更加青睐MVVM,拌上ReactiveCocoa或者RxSwift,這道菜可以做的更加絢爛多彩!當然,正如唐巧在文中所言:ReactiveCocoa 和 MVVM 不應該被神化,我們需要保持的是一個擁抱變化的心,以及理性分析的態度。在新技術的面前,不盲從,也不守舊,一切的決策都應該建立在認真分析的基礎上,這樣才能應對技術的變化!

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved