iOS 我理解的MVC和MVVM

一、MVC模式

MVC模式算是老生常談的開(kāi)發(fā)模式了,簡(jiǎn)單的說(shuō),M單純的數(shù)據(jù)模型,V就是視圖,例如一個(gè)UIButton、一個(gè)列表視圖Table或者自定義封裝的View等,C則是controller控制器,它是M和V的紐帶,負(fù)責(zé)業(yè)務(wù)邏輯部分,包括處理M數(shù)據(jù)模型、管理V視圖(創(chuàng)建、展示、釋放等)、響應(yīng)V的事件等等。MVC的本質(zhì)就是將數(shù)據(jù)的存儲(chǔ)M和數(shù)據(jù)的展示V進(jìn)行隔離,以提高代碼的復(fù)用性和擴(kuò)展性。

MVC
借用別人的圖

MVC模式大體如上圖所示。我們可以看到,Controller可以和Model、View進(jìn)行通信,而Model和View是相互隔離的,它們的關(guān)聯(lián)都是通過(guò)Controller來(lái)實(shí)現(xiàn)的,這樣一來(lái),就可以提高兩者的復(fù)用性和可擴(kuò)展性,即相同的Model可以有不同的展現(xiàn)形式,同樣的,相同的View可以有不同的模型數(shù)據(jù),達(dá)到了解耦和重用的目的。
如果Model發(fā)生了變化,那么就通過(guò)Notification和KVO的方式傳遞給Controller,Controller可以直接根據(jù)Model決定View的展示形式。View如果接受響應(yīng)事件則通過(guò)delegate,target-action,block等方式告訴Controller的狀態(tài)變化。Controller進(jìn)行業(yè)務(wù)的處理,然后再控制View的展示。

舉例說(shuō)明:
我們假設(shè)蘋(píng)果根據(jù)買(mǎi)iPhone的人給予不同的優(yōu)惠,學(xué)生優(yōu)惠20%,it民工優(yōu)惠50%,其他不優(yōu)惠。

//客戶(hù)類(lèi)

typedef NS_ENUM(NSInteger, CustomerType) {
    CustomerTypeStudent,
    CustomerTypeiT,
    CustomerTypeOther,
};

@interface Customer : NSObject

@property (nonatomic, assign) CustomerType customerType;

@end

//iPhone類(lèi)

@interface iPhone : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *price;

@end

//VC類(lèi)

@interface ViewController ()

@property (nonatomic, strong) iPhone *iphone;
@property (nonatomic, strong) Customer *customer;

@property (weak, nonatomic) IBOutlet UILabel *lblName;
@property (weak, nonatomic) IBOutlet UILabel *lblPrice;
@property (weak, nonatomic) IBOutlet UILabel *lblDiscount;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.title = @"手機(jī)優(yōu)惠";

    self.lblName.text = self.iphone.name;
    self.lblPrice.text = self.iphone.price;

    if (self.customer.customerType == CustomerTypeStudent) {
        self.lblDiscount.text = @"優(yōu)惠20%";
    }
    else if (self.customer.customerType == CustomerTypeiT) {
        self.lblDiscount.text = @"優(yōu)惠50%";
    }
    else {
        self.lblDiscount.text = @"沒(méi)有優(yōu)惠";
    }
}

@end

這是我們開(kāi)發(fā)過(guò)程中最經(jīng)典的MVC案例,將業(yè)務(wù)邏輯部分全都寫(xiě)在Controller類(lèi)里面,根據(jù)Model模型來(lái)展示View。這樣做是沒(méi)有錯(cuò)的,但是如果業(yè)務(wù)邏輯相當(dāng)復(fù)雜,代碼又不規(guī)范、沒(méi)有調(diào)理性,開(kāi)發(fā)下來(lái),controller會(huì)變得相當(dāng)?shù)挠纺[,越來(lái)越難維護(hù)。即使做好了相關(guān)的代碼分類(lèi)和注釋?zhuān)麄€(gè)業(yè)務(wù)邏輯看起來(lái)也是相當(dāng)?shù)念^疼,因?yàn)橛行I(yè)務(wù)處理并不是我們想要關(guān)注的。


二、MVVM模式

針對(duì)MVC的缺陷,MVVM模式出現(xiàn)了,既然我們并不太想關(guān)注業(yè)務(wù)是怎么實(shí)現(xiàn)的,我們能不能將業(yè)務(wù)實(shí)現(xiàn)的部分分離出來(lái),當(dāng)我想要某個(gè)業(yè)務(wù)的時(shí)候(比如數(shù)據(jù)的獲取處理成Model、按鈕事件的響應(yīng)、頁(yè)面的跳轉(zhuǎn)等),我只需要告知其就可以了,這樣的Controller只包含了業(yè)務(wù)邏輯部分,而具體的實(shí)現(xiàn)部分則是透明的,Controller并不需要關(guān)心怎么實(shí)現(xiàn),這樣,Controller變得相當(dāng)清爽,我們的業(yè)務(wù)部分相當(dāng)清晰。


MVVM

這樣看來(lái),MVVM中的VM就是Controller+Model(具有業(yè)務(wù)實(shí)現(xiàn)功能),MVVM其實(shí)應(yīng)該叫做MVCM,可能是因?yàn)樵谶@樣的模型下,Controller的管理功能被轉(zhuǎn)移削弱,只負(fù)責(zé)View的管理等部分功能而使用V來(lái)定義吧。
從圖上看出,View-Model是Controller業(yè)務(wù)的代理者,而原來(lái)的Controller不再直接接觸Model,Model的擁有者已然移交給了View-Model。

原來(lái)的例子使用MVVM:

//新建一個(gè)viewModel
//.h文件

@interface viewModel : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *price;
@property (nonatomic, strong) NSString *discount;

- (id)initWithCustomer:(Customer *)customer iphone:(iPhone *)iphone;

@end

//.m文件

@interface viewModel ()

@property (nonatomic, strong) iPhone *iphone;
@property (nonatomic, strong) Customer *customer;

@end

@implementation viewModel

- (id)initWithCustomer:(Customer *)customer iphone:(iPhone *)iphone
{
    if (self = [super init]) {
        _customer = customer;
        _iphone = iphone;
        [self bindData];
    }
    return self;
}

- (void)bindData
{
    self.name = _iphone.name;
    self.price = _iphone.price;

    if (self.customer.customerType == CustomerTypeStudent) {
        self.discount = @"優(yōu)惠20%";
    }
    else if (self.customer.customerType == CustomerTypeiT) {
        self.discount = @"優(yōu)惠50%";
    }
    else {
        self.discount = @"沒(méi)有優(yōu)惠";
    }
}

@end

//VC

@interface ViewController ()

@property (nonatomic, strong) viewModel *viewModel;

@property (weak, nonatomic) IBOutlet UILabel *lblName;
@property (weak, nonatomic) IBOutlet UILabel *lblPrice;
@property (weak, nonatomic) IBOutlet UILabel *lblDiscount;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.title = @"手機(jī)優(yōu)惠";

    self.lblName.text = self.viewModel.name;
    self.lblPrice.text = self.viewModel.price;
    self.lblDiscount.text = self.viewModel.discount;

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

比較可以看出,Controller里面僅僅做了展示數(shù)據(jù)的操作,而這數(shù)據(jù)怎么來(lái)的,Controller并不關(guān)心,而這部分的業(yè)務(wù)邏輯移交給了viewModel來(lái)處理,而viewModel則將處理結(jié)果開(kāi)放出來(lái),通過(guò)屬性或者代理、block回調(diào)傳給Controller。


三、MVVM優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

1、簡(jiǎn)化Controller業(yè)務(wù)邏輯

它可以為Controller分擔(dān)部分業(yè)務(wù),瘦身Controller,讓開(kāi)發(fā)者不再需要在Controller里尋找業(yè)務(wù)的實(shí)現(xiàn)部分,而關(guān)注Controller的業(yè)務(wù)流程。

缺點(diǎn)

1、類(lèi)數(shù)量增加、復(fù)用性差

實(shí)際上,View-Model只是一個(gè)特殊的業(yè)務(wù)類(lèi)(例如數(shù)據(jù)請(qǐng)求類(lèi)),特殊性就在于,它的針對(duì)性強(qiáng),是Controller的業(yè)務(wù)代理者,通常一個(gè)VC都分配一個(gè)View-Model,所以View-Model通常不復(fù)用。

2、調(diào)用復(fù)雜度增加

由于數(shù)據(jù)都是從viewModel來(lái),想想突然來(lái)了一個(gè)新人,一看代碼,不知道真實(shí)的模型是誰(shuí)。比如常用tableview的數(shù)據(jù)源,一般都是一個(gè)數(shù)組,如果不斷的通過(guò)viewModel去取,溝通上沒(méi)有那么直接。況且每封一層,意味著要寫(xiě)很多代碼去融合他們的轉(zhuǎn)換。

四、體會(huì)

1、在業(yè)務(wù)簡(jiǎn)單的頁(yè)面,使用MVC最合適,Controller直接處理業(yè)務(wù),調(diào)用Model便捷。

2、業(yè)務(wù)復(fù)雜的頁(yè)面最好使用MVVM,這樣業(yè)務(wù)模塊化,管理方便,簡(jiǎn)化Controller。

3、最重要一點(diǎn),MVVM中的viewModel是Controller業(yè)務(wù)邏輯的分擔(dān)者,請(qǐng)基于MVC原則下嘗試MVVM


五、鳴謝

1、非常感謝作者:JamesYu,對(duì)MVVM模式解釋的很好,舉的例子也非常好,很容易理解。

2、原文地址:談?wù)凪VC和MVVM

3、如果我理解的不對(duì)的地方,還望大家指正,謝謝。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容