iOS 我理解的MVC和MVVM

一、MVC模式

MVC模式算是老生常谈的开发模式了,简单的说,M单纯的数据模型,V就是视图,例如一个UIButton、一个列表视图Table或者自定义封装的View等,C则是controller控制器,它是M和V的纽带,负责业务逻辑部分,包括处理M数据模型、管理V视图(创建、展示、释放等)、响应V的事件等等。MVC的本质就是将数据的存储M和数据的展示V进行隔离,以提高代码的复用性和扩展性。

MVC
借用别人的图

MVC模式大体如上图所示。我们可以看到,Controller可以和Model、View进行通信,而Model和View是相互隔离的,它们的关联都是通过Controller来实现的,这样一来,就可以提高两者的复用性和可扩展性,即相同的Model可以有不同的展现形式,同样的,相同的View可以有不同的模型数据,达到了解耦和重用的目的。
如果Model发生了变化,那么就通过Notification和KVO的方式传递给Controller,Controller可以直接根据Model决定View的展示形式。View如果接受响应事件则通过delegate,target-action,block等方式告诉Controller的状态变化。Controller进行业务的处理,然后再控制View的展示。

举例说明:
我们假设苹果根据买iPhone的人给予不同的优惠,学生优惠20%,it民工优惠50%,其他不优惠。

//客户类

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

@interface Customer : NSObject

@property (nonatomic, assign) CustomerType customerType;

@end

//iPhone类

@interface iPhone : NSObject

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

@end

//VC类

@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 = @"手机优惠";

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

    if (self.customer.customerType == CustomerTypeStudent) {
        self.lblDiscount.text = @"优惠20%";
    }
    else if (self.customer.customerType == CustomerTypeiT) {
        self.lblDiscount.text = @"优惠50%";
    }
    else {
        self.lblDiscount.text = @"没有优惠";
    }
}

@end

这是我们开发过程中最经典的MVC案例,将业务逻辑部分全都写在Controller类里面,根据Model模型来展示View。这样做是没有错的,但是如果业务逻辑相当复杂,代码又不规范、没有调理性,开发下来,controller会变得相当的臃肿,越来越难维护。即使做好了相关的代码分类和注释,整个业务逻辑看起来也是相当的头疼,因为有些业务处理并不是我们想要关注的。


二、MVVM模式

针对MVC的缺陷,MVVM模式出现了,既然我们并不太想关注业务是怎么实现的,我们能不能将业务实现的部分分离出来,当我想要某个业务的时候(比如数据的获取处理成Model、按钮事件的响应、页面的跳转等),我只需要告知其就可以了,这样的Controller只包含了业务逻辑部分,而具体的实现部分则是透明的,Controller并不需要关心怎么实现,这样,Controller变得相当清爽,我们的业务部分相当清晰。


MVVM

这样看来,MVVM中的VM就是Controller+Model(具有业务实现功能),MVVM其实应该叫做MVCM,可能是因为在这样的模型下,Controller的管理功能被转移削弱,只负责View的管理等部分功能而使用V来定义吧。
从图上看出,View-Model是Controller业务的代理者,而原来的Controller不再直接接触Model,Model的拥有者已然移交给了View-Model。

原来的例子使用MVVM:

//新建一个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 = @"优惠20%";
    }
    else if (self.customer.customerType == CustomerTypeiT) {
        self.discount = @"优惠50%";
    }
    else {
        self.discount = @"没有优惠";
    }
}

@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 = @"手机优惠";

    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里面仅仅做了展示数据的操作,而这数据怎么来的,Controller并不关心,而这部分的业务逻辑移交给了viewModel来处理,而viewModel则将处理结果开放出来,通过属性或者代理、block回调传给Controller。


三、MVVM优缺点

优点:

1、简化Controller业务逻辑

它可以为Controller分担部分业务,瘦身Controller,让开发者不再需要在Controller里寻找业务的实现部分,而关注Controller的业务流程。

缺点

1、类数量增加、复用性差

实际上,View-Model只是一个特殊的业务类(例如数据请求类),特殊性就在于,它的针对性强,是Controller的业务代理者,通常一个VC都分配一个View-Model,所以View-Model通常不复用。

2、调用复杂度增加

由于数据都是从viewModel来,想想突然来了一个新人,一看代码,不知道真实的模型是谁。比如常用tableview的数据源,一般都是一个数组,如果不断的通过viewModel去取,沟通上没有那么直接。况且每封一层,意味着要写很多代码去融合他们的转换。

四、体会

1、在业务简单的页面,使用MVC最合适,Controller直接处理业务,调用Model便捷。

2、业务复杂的页面最好使用MVVM,这样业务模块化,管理方便,简化Controller。

3、最重要一点,MVVM中的viewModel是Controller业务逻辑的分担者,请基于MVC原则下尝试MVVM


五、鸣谢

1、非常感谢作者:JamesYu,对MVVM模式解释的很好,举的例子也非常好,很容易理解。

2、原文地址:谈谈MVC和MVVM

3、如果我理解的不对的地方,还望大家指正,谢谢。

你可能感兴趣的:(iOS 我理解的MVC和MVVM)