架构模式-④MVC与MVVM

[toc]

一、框架

二、MVC,MVP 和 MVVM 的图示

MVC,MVP 和 MVVM 的图示

三、MVC与MVVM

1、MVC的开发模式

MVC是模型、视图、控制器开发模式,对于iOS SDK,所有的View都是视图层的,它应该独立于模型层,由视图器来控制。所有的用户数据都是模型层,它应该独立于视图。所有的ViewController都是视图器,由它负责控制视图,访问模型数据。

2、关于MVC 和 MVVM 的区别

MVVM 介绍

1.传统的MVC设计模式

mvc_1

MVP设计模式

mvp_1

用户在view上的操作,会通过vm对model进行数据的修改;

数据的修改引起的属性变化会通知到vm上;

vm根据变化进行view UI的更新;

MVVM 模式将 Presenter 改名为 ViewModel,基本上与 MVP 模式完全一致。

img

唯一的区别是,它采用双向绑定(data-binding):View的变动,自动反映在 ViewModel,反之亦然。

MVVM的代码实现

ViewModel设计的了解,请进入项目:《DvlproadDesignPatternCollect》中的 CJViewModelDemo
该项目采用blockdelegateKVORAC四种方式介绍ViewModel的设计。 详情请查看:CJViewModelDemoViewModelDemos 文件夹下的代码

Flutter 中可查看 001-UIKit-CQDemo-Flutter 项目中的 tsdemodemo_flutter 工程里的 architecture 文件目录

该MVVM设计在其他项目中的使用,可见:CJStandardProject 的 LoginViewModel.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//  LoginViewModel.h
#import <Foundation/Foundation.h>
@protocol LoginViewModelDelegate <NSObject>

/// userName 的有效性发生变化
- (void)logic_checkUserNameWithValid:(BOOL)valid;
/// password 的有效性发生变化
- (void)logic_checkPasswordWithValid:(BOOL)valid;
/// 登录按钮 的有效性发生变化
- (void)logic_checkLoginWithValid:(BOOL)valid;

@end



@interface LoginViewModel : NSObject {

}
@property (nonatomic, weak) id<LoginViewModelDelegate> delegate;
@property (nonatomic, copy, readonly) NSString *userName;
@property (nonatomic, copy, readonly) NSString *password;

- (instancetype)initWithUserName:(NSString *)userName password:(NSString *)password;

#pragma mark - Update
- (void)updateUserName:(NSString *)userName;
- (void)updatePassword:(NSString *)password;

#pragma mark - Do
/// 检查是否可登录
- (NSString *)checkLoginCondition;

/// 执行登录
- (void)loginWitLoginSuccess:(void (^)(NSString *successMessage, DemoUser *user))loginSuccess
loginFailure:(void (^)(NSString *errorMessage))loginFailure;

@end

其他MVVM说明示例

设有如下原始Model

1
2
3
4
5
6
7
8
9
10
@interface Person : NSObject

- (instancetype)initwithSalutation:(NSString *)salutation firstName:(NSString *)firstName lastName:(NSString *)lastName birthdate:(NSDate *)birthdate;

@property (nonatomic, readonly) NSString *salutation;
@property (nonatomic, readonly) NSString *firstName;
@property (nonatomic, readonly) NSString *lastName;
@property (nonatomic, readonly) NSDate *birthdate;

@end

则如果仅有此Model的话,我们在PersonViewController中

1
2
3
4
5
6
7
8
9
10
11
12
- (void)viewDidLoad {
[super viewDidLoad];

NSString *nameText = nil;
if (self.personModel.salutation.length > 0) {
nameText = [NSString stringWithFormat:@"%@ %@ %@", self.personModel.salutation, self.personModel.firstName, self.personModel.lastName];
} else {
nameText = [NSString stringWithFormat:@"%@ %@", self.personModel.firstName, self.personModel.lastName];
}

self.nameLabel.text = nameText;
}

而如果我们进而增加一个ViewModel,则如果我们PersonViewController中可以简化成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@implementation PersonViewModel

- (instancetype)initWithPerson:(Person *)person {
self = [super init];
if (!self) return nil;

_person = person;
if (person.salutation.length > 0) {
_nameText = [NSString stringWithFormat:@"%@ %@ %@", self.person.salutation, self.person.firstName, self.person.lastName];
} else {
_nameText = [NSString stringWithFormat:@"%@ %@", self.person.firstName, self.person.lastName];
}

return self;
}

@end

// 此时我们PersonViewController中可以简化成
- (void)viewDidLoad {
[super viewDidLoad];

self.nameLabel.text = self.personViewModel.nameText;
}

END