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