从MVC到MVP

前言

以前本人一直用的都是MVC的设计模式去开发应用的。封装MVC的基类等等,和一些工具类配合开发。甚至去过的公司也都是这种方式,就连苹果的基类名字都是以View,Controller(UIView,UIViewController等)结尾的。但是这次发现公司controller层代码量异常的庞大(想找个方法,滑动半天都找不到,好累…,主要是写法不规范,冗余代码太多),虽然重构了基类,从而减重了controller类,但是发现还是过于冗杂。公司的网络请求一个界面有多个,导致一个controller有好多网络请求的代码。之后尝试用mvp设计模式去重构发现好多了,层次分明了,世界清净了哈哈。

那是不是iOS开发只能用MVC的设计模式呢,显然不是的。MVC,MVP,MVVM(统称MVX系列)其实都可以的。其实android现在普遍在用MVP的设计模式,前端(vue等)都在用MVVM的设计模式。

有这么多的设计模式,iOS开发应该选用哪种设计模式呢,哪种更好呢,带着这些问题我们去探索一下这些设计模式在iOS开发上的应用,特点,以及他们不同。看看哪种设计模式更适合自己。

MVC

M:Model,它是模型类,就是有很多属性,每个属性名字和后台返回的字段名相同。

V:View,它是视图类,如继承与UIView类的所有类都可以认为是V层。这个类里存放的都是和视图相关的逻辑代码。

C:Controller,它是控制器类,这里是主要写各种逻辑的地方,这里控制着M层数据源,控制着View的展示等等。

三者关系是,c层持有m层,持有v层

可见C层控制着view的展示,控制着M数据的填充,一些点击事件一些逻辑,甚至网络请求代码等等。这使得C层异常的庞大。为了解决这个问题,我们引入了各种工具类,甚至封装各种基类试图用这些工具类封装的代码去减轻controller。但是事实表明这样做还是不能对controller彻底瘦身,controller层还是庞大。

还有个问题是层次并不是那么的分明,比如controller层是视图控制器,那就控制视图好了嘛,干嘛要负责那么多任务呢。既要负责网络的请求,又要负责各种数据层的逻辑,这有些违反了视图控制器的这个概念。

可见传统的MVC设计模式有着不可避免的两大问题,controller庞大,层次不明。为了解决这个问题,从而引出了MVP的设计模式

MVP

M:Model,它是模型类,就是有很多属性,每个属性名字和后台返回的字段名相同。

V:View,它是视图类,如继承与UIView类的所有类都可以认为是V层,并且Controller也属于V层,即继承与UIView,UIViewController类的所有类都属于V层。这个类里存放的都是和视图相关的逻辑代码。并且controller类里存放的是一些胶水代码(就是起到粘合作用的代码)。

P:Presenter,它是P层,这里是主要写网络请求,数据逻辑的地方。处理和视图无关的数据逻辑等。这个类不该持有v层,也就是不该#import <UIKit/UIKit.h>

三者关系是,v层持有p层,p层持有m层,并回调给v层。

从上面介绍可以看出,MVC中的C层中的网络请求,数据逻辑代码被移动到了MVP中的P层中。这样做一是可以减轻MVC中的C层的代码量,又可以使得层次分明。

下边我们用一些伪代码来进一步探索MVP的应用,其实和MVC一样,我们也需要封装出一套MVP的基类。用这些基类可以使得我们编码更方便。

在这里插入图片描述

//MyModel类
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface MyModel : NSObject

/** 头像 */
@property (copy, nonatomic) NSString *img;
/** 昵称 */
@property (copy, nonatomic) NSString *nickName;
@end

NS_ASSUME_NONNULL_END


//MyVC类
#import "MyVC.h"
#import "MyPresenter.h"

@interface MyVC ()
@property (strong, nonatomic) MyPresenter *presenter;
@end

@implementation MyVC

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //持有P层
    self.presenter = [[MyPresenter alloc] init];
    [self setUpUI];
    //网络请求
    [self fetchData];
}

- (void)setUpUI{
    //布局代码...
}

- (void)fetchData{
    [self.presenter fetchData:^(MyModel * _Nonnull model, NSError * _Nonnull error) {
        if (error) {
            //出错处理
        }else{
            //数据赋值
            
        }
    }];
}
@end

//MyPresenter类
#import "MyPresenter.h"
#import "MyModel.h"
#import <BSUtilsBaseRequestManager.h>

@implementation MyPresenter
- (void)fetchData:(void(^)(MyModel *model, NSError * _Nonnull error))finishBlk{
    [[BSUtilsBaseRequestManager new] postWithUrl:@"xxx" parmas:@{} finishBlk:^(NSDictionary * _Nonnull responseObject, NSError * _Nonnull error) {
        //json转model
        //数据整理,数据逻辑
        if (finishBlk) {
            finishBlk(model,error);
        }
    }];
}
@end

总结

通过比较分析可知,传统MVC,C层代码量庞大,层次不分明。MVP设计模式把网络请求,数据层逻辑抽出来放到P层,这样解决了C层代码量庞大问题,也解决了层次分明问题。

其实采用mvp设计模式后不仅仅解决了c层庞大问题,层次分明问题。而且p层是复用的,比如我们一个地方用到了点赞功能,我们就可以持有点赞功能的p层去调用相应的点赞方法即可。如果是用传统的mvc设计模式,网络请求都是写在了c层,我们每次都得复制粘贴点赞的请求方法,异常的麻烦,如果想复用这段代码,就要考虑写成类方法,并且要考虑耦合性问题,还是比较麻烦的。但是用mvp后所有的网络请求的p层相当于都是复用的了,随时都可以无耦合的调用。

当你用了mvp设计模式后可能有时会发现p层代码量很少,但是却独占一个类,这时候可以考虑p层合并。比如我们有两个界面,一个界面是一级分类,另一个界面是二级分类。这时候两个界面我们可以考虑用一个p层,两个界面的网络请求代码都放到一个层中。但是有时候是无法合并的,因为这个p层和其他p层没有相同的含义,这时候硬是合并是不合理的。这时候确实会存在一个p层就一个网络请求的方法但是却独占一个类,这是没有办法的。但是这样也确实是层次分明了,这个网络请求代码可以复用了,有利也有弊吧。但是我觉得利是大于弊的,比起mvc我还是比较喜欢用mvp的设计模式。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值