1、概述
MVP的全稱為Model-View-Presenter,Model提供數(shù)據(jù),View負(fù)責(zé)顯示,Controller/Presenter負(fù)責(zé)邏輯的處理。MVP與MVC有著一個(gè)重大的區(qū)別:在MVP中View并不直接使用Model,它們之間的通信是通過(guò)Presenter (MVC中的Controller)來(lái)進(jìn)行的,所有的交互都發(fā)生在Presenter內(nèi)部,而在MVC中View會(huì)直接從Model中讀取數(shù)據(jù)而不是通過(guò) Controller。
MVP從視圖層中分離了行為(事件響應(yīng))和狀態(tài)(屬性,用于數(shù)據(jù)展示),它創(chuàng)建了一個(gè)視圖的抽象,也就是presenter層,而視圖就是P層的『渲染』結(jié)果。P層中包含所有的視圖渲染需要的動(dòng)態(tài)信息,包括視圖的內(nèi)容(text、color)、組件是否啟用(enable),除此之外還會(huì)將一些方法暴露給視圖用于某些事件的響應(yīng)。
2、MVP架構(gòu)和各層職責(zé)對(duì)比

在 MVP 中,Presenter 可以理解為松散的控制器,其中包含了視圖的 UI 業(yè)務(wù)邏輯,所有從視圖發(fā)出的事件,都會(huì)通過(guò)代理給 Presenter 進(jìn)行處理;同時(shí),Presenter 也通過(guò)視圖暴露的接口與其進(jìn)行通信。
各層職責(zé)如下:
VC層:
- view的布局和組裝
- view的生命周期控制
- 通知各個(gè)P層去獲取數(shù)據(jù)然后渲染到view上面展示
controller層
- 生成view,實(shí)現(xiàn)view的代理和數(shù)據(jù)源
- 綁定view和presenter
- 調(diào)用presenter執(zhí)行業(yè)務(wù)邏輯
model層
- 業(yè)務(wù)邏輯封裝
- 提供數(shù)據(jù)接口給controller使用
- 數(shù)據(jù)持久化存儲(chǔ)和讀取
- 作為數(shù)據(jù)模型存儲(chǔ)數(shù)據(jù)
Presenter層職責(zé)
- 實(shí)現(xiàn)view的事件處理邏輯,暴露相應(yīng)的接口給view的事件調(diào)用
- 調(diào)用model的接口獲取數(shù)據(jù),然后加工數(shù)據(jù),封裝成view可以直接用來(lái)顯示的數(shù)據(jù)和狀態(tài)
- 處理界面之間的跳轉(zhuǎn)(這個(gè)根據(jù)實(shí)際情況來(lái)確定放在P還是C)
3、IOS中P層的具體實(shí)現(xiàn)
這是一個(gè)Presenter的Protocol, 所有的P層的類都要遵循這個(gè)Protocol
#import /**
作為P : presenter 是管理 view viewController model這個(gè)三個(gè)中間人,負(fù)責(zé)UI刷新
視圖的交互總是和VC 關(guān)聯(lián)著的
*/
@protocol TGPresenterProtocol @optional
// 處理View視圖相關(guān)操作 -- 協(xié)議的遵守者
- (void)setView:(NSObject *)view;
// 處理事件的相關(guān)響應(yīng)
- (void)setViewController:(UIViewController *)viewController;
// 展示
- (void)present;
// 加載model
- (void)presentWithModel:(id)model viewController:(UIViewController *)viewController;
@end
可以看出, P層是可以拿到view或者viewController的, 并且可以在實(shí)現(xiàn)set方法的時(shí)候做一些事情. 這個(gè)稍后再講另外, P層還可以展示數(shù)據(jù), 直接展示數(shù)據(jù), present方法, 利用模型展示數(shù)據(jù), 利用presentWithModel:方法.比如, 在一個(gè)遵循了TGPresenterProtocol的Presenter類中,把需要管理的view傳遞給P
- (instancetype)initWithTableView:(UITableView *)view{
self = [super init];
if (!self) {
return nil;
}
_view = view;
_view.delegate = self;
_view.dataSource = self;
_view.separatorStyle = UITableViewCellSeparatorStyleNone;
// 自適應(yīng)高度
_view.rowHeight = UITableViewAutomaticDimension;
_view.estimatedRowHeight = 100;
return self;
}
- (void)setView:(UITableView *)view{
// 設(shè)置視圖
_view = view;
_view.delegate = self;
_view.dataSource = self;
_view.separatorStyle = UITableViewCellSeparatorStyleNone;
// 自適應(yīng)高度
_view.rowHeight = UITableViewAutomaticDimension;
_view.estimatedRowHeight = 100;
}
比如上面的代碼, 將tableView的數(shù)據(jù)源和代理都給了P, 那么P就相當(dāng)于行使了控制器的權(quán)力, 當(dāng)P層拿到數(shù)據(jù)時(shí)(P層是持有Model的):
- (void)loadHPData{
NSString *dataPath = [[NSBundle mainBundle] pathForResource:@"testCellData" ofType:@"json"];
NSData *jsonData = [NSData dataWithContentsOfFile:dataPath];
NSError *error;
NSDictionary *dataDic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:&error];
if (error) {
NSLog(@"error = %@",error.localizedDescription);
}
NSLog(@"dataDic = %@",dataDic);
// model 要處理好數(shù)據(jù)的顯示格式
self.hpModel = [[CellSelfSizeModel alloc] initWithDic:dataDic];
// 刷新
[self present];
}
走Present方法, 實(shí)際就是tableView的reloadData,然后重走tableView的數(shù)據(jù)源方法. 將數(shù)據(jù)分發(fā)給cell去展示,這樣就實(shí)現(xiàn)了Controller, View, Model的解耦. 控制器做的事情只有如下幾件:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.title = @"MVP Demo";
// 布局
[self initViews];
[self setUpConstraints];
self.hpPresenter = [TGHPPresenter new];
// 視圖對(duì)象
self.hpPresenter.view = self.tableView;
// 控制器對(duì)象
self.hpPresenter.viewController = self;
// 外邊是要傳入?yún)⑦M(jìn)去的 -- 數(shù)據(jù)模型
[self.hpPresenter loadHPData];
}
只需要初始化P層, 然后調(diào)P層的接口就可以了. 至于P層內(nèi)部的邏輯, 我不需要知道,其他的V層和M層。
1、V層也只專注于視圖的創(chuàng)建
2、M層只專注于模型的構(gòu)建(字典->模型)
4、MVP優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
1、降低耦合度
2、模塊職責(zé)劃分明顯
3、利于測(cè)試驅(qū)動(dòng)開(kāi)發(fā)
4、代碼復(fù)用
5、隱藏?cái)?shù)據(jù)
缺點(diǎn):
1、由于對(duì)視圖的渲染放在了Presenter中,所以視圖和Presenter的交互會(huì)過(guò)于頻繁。如果Presenter過(guò)多地渲染了視圖,往往會(huì)使得它與特定的視圖的聯(lián)系過(guò)于緊密。一旦視圖需要變更,那么Presenter也需要變更了。
參考博客
https://blog.csdn.net/sheng52406/article/details/46679975/
http://m.itdecent.cn/p/a73953403fbf
https://baijiahao.baidu.com/s?id=1650972658696833051&wfr=spider&for=pc