美文网首页好东西小知识点
根据频繁的产品需求变更决定你的MVC、MVP设计、MPC再到组件

根据频繁的产品需求变更决定你的MVC、MVP设计、MPC再到组件

作者: 嘴爷 | 来源:发表于2017-09-06 09:12 被阅读171次

一个项目从开发到完成可能会融合进好多设计模式,MVCMVPMVVM或者MVC+MVP等各种的组合。


假定老板提出让你做一款美食APP,然后你产品就咔咔咔的去设计了,然后设计了如下的东东:

DISH.png

就这么点东西,你会选择MVP么?显然MVC就已经足够了,如果MVP,那就要多写几个文件。如果写的足够好的话,MVC能够很容易的移至到MVP中。我们直接上一坨代码,标记下几个类文件充当MVC中的角色,发现MVC真的能满足。

mvc.png

老板又说了,你的菜得有个分类啊,凉菜炒菜主食酒水 等等,你得给左侧加个分类啊。我们暂且理解,就百度外卖那个样子。然后产品就是设计去了,设计如下的东东:

CATE.png

一个页面左右两个列表,如果MVC去写倒是也行,但是你要考虑到如下情况

  • 如果用MVC写,控制层是不是很臃肿?
  • 如果哪天老板说左侧列表我不要了,你砍掉一个功能容易么?会影响到右侧列表么?
  • 如果说这个页面再给你个人去做,你怎么去做?代码你怎么合并?

MVP就显示出它的优势了,比如,左侧用MVC设计、右侧也用MVC设计,最后由统一的P层去调用。MVP中嵌套的MVC 我就理解为ModelViewController(M和V的协调者)
说多了没用,先看一个结构图,再上一坨代码,代码里标记下各部分在MVP中充当的角色

mvp.png

最后效果如下:

liandong.gif

我们看下Presenter层都做了什么?

  • 把各个页面拼接到一起
  • 实现各个模块中的协议进而实现:协调分类控制器和菜品控制器联动、处理点击菜品时的业务

Presenter 中的代码如下:


@interface Presenter ()<CategoryTableViewControllerDelegate, DishTableViewControllerDelegate>

/** 分类控制器 */
@property (nonatomic, strong) CategoryTableViewController* categoryVC;

/** 菜品控制器 */
@property (nonatomic, strong) DishTableViewController* dishVC;

@end

@implementation Presenter

#pragma mark -
#pragma mark - life circle
- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    // Do any additional setup after loading the view.
    
    self.categoryVC = [[CategoryTableViewController alloc] initWithStyle:(UITableViewStylePlain)];
    self.categoryVC.delegate = self;
    [self.view addSubview:self.categoryVC.tableView];
    [self addChildViewController:self.categoryVC];
    
    
    self.dishVC = [[DishTableViewController alloc] initWithStyle:(UITableViewStylePlain)];
    self.dishVC.delegate = self;
    [self.view addSubview:self.dishVC.tableView];
    [self addChildViewController:self.dishVC];
    
    
    [self.categoryVC.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.view.mas_top).offset(0);
        make.left.equalTo(self.view.mas_left).offset(0);
        make.bottom.equalTo(self.view.mas_bottom).offset(0);
        make.width.mas_equalTo(@(100));
    }];
    
    [self.dishVC.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.categoryVC.tableView.mas_top).offset(0);
        make.right.equalTo(self.view.mas_right).offset(0);
        make.bottom.equalTo(self.view.mas_bottom).offset(0);
        make.left.equalTo(self.categoryVC.tableView.mas_right).offset(0);
    }];
    
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark -
#pragma mark - CategoryTableViewControllerDelegate
-(void)categoryTableViewController:(CategoryTableViewController *)controller didSelectCategoryId:(NSInteger)categoryId{

    [self.dishVC scrollRowWithCategoryId:categoryId];
}

#pragma mark -
#pragma mark - DishTableViewControllerDelegate
-(void)dishTableViewController:(DishTableViewController *)controller willShowCategoryId:(NSInteger)categoryId{
    
    [self.categoryVC selectRowWithCategoryId:categoryId];
}

-(void)dishTableViewController:(DishTableViewController *)controller didSelectDish:(DishModel *)dishModel{
    
    NSLog(@"当前选中的菜品名称:%@", dishModel.dishName);
}


那么在分类控制器中,接口如下:


@class CategoryTableViewController;
@protocol CategoryTableViewControllerDelegate <NSObject>
@optional


/**
 选中分类的时候

 @param controller 分类控制器
 @param categoryId 当前选中的分类id
 */
-(void)categoryTableViewController:(CategoryTableViewController*)controller didSelectCategoryId:(NSInteger)categoryId;

@end

@interface CategoryTableViewController : UITableViewController

/** 代理 */
@property (nonatomic, weak) id<CategoryTableViewControllerDelegate> delegate;


/**
 根据分类ID选择某个分类

 @param categoryId 分类id
 */
-(void)selectRowWithCategoryId:(NSInteger)categoryId;

@end

那么在菜品控制器中,接口如下:


@class DishTableViewController;
@class DishModel;
@protocol DishTableViewControllerDelegate <NSObject>
@optional


/**
 滚动菜品section变化的时候

 @param controller 菜品控制器
 @param categoryId 当前最顶部展现的菜品的分类id
 */
-(void)dishTableViewController:(DishTableViewController*)controller willShowCategoryId:(NSInteger)categoryId;


/**
 选中一个菜品的时候

 @param controller 菜品控制器
 @param dishModel 菜品数据模型
 */
-(void)dishTableViewController:(DishTableViewController*)controller didSelectDish:(DishModel*)dishModel;

@end

@interface DishTableViewController : UITableViewController

/** 代理 */
@property (nonatomic, weak) id<DishTableViewControllerDelegate> delegate;


/**
 根据分类ID滚动某个菜品

 @param categoryId 分类id
 */
-(void)scrollRowWithCategoryId:(NSInteger)categoryId;

@end

拼接两个tableView的时候添加约束并没有达到预期的效果,后来发现是导航的 translucent属性影响,解决办法如下

translucent.png

假如老板又说了,顶部再给我加个地址选择的区域,那么MVP显然优势就来了。加一个地址信息模块,跟CategoryDish平级,模块内部MVC、MVP都无所谓了。只需要在Presenter内部调用对应模块的接口即可。


感谢您阅读完毕,如有疑问,欢迎添加QQ:714387953(蜗牛上高速)。
github:https://github.com/yhl714387953/MVP
如果有错误,欢迎指正,一起切磋,共同进步
如果喜欢可以Follow、Star、Fork,都是给我最大的鼓励。

下一篇着重写MPC和组件化方案

相关文章

网友评论

    本文标题:根据频繁的产品需求变更决定你的MVC、MVP设计、MPC再到组件

    本文链接:https://www.haomeiwen.com/subject/xndmjxtx.html