美文网首页iOS专题资源__系统知识点workOC技术
MVC/MVP/MVVM 三种设计模式简介附demo

MVC/MVP/MVVM 三种设计模式简介附demo

作者: _方丈 | 来源:发表于2017-01-05 13:48 被阅读1061次

    前言:说到设计模式,许多人认为是很高深的东西,其实许多都是由简单演变而来,或许MVC模式并不难理解因为熟悉,其他模式其实也是同样如此。MVC ->MVP ->MVVM 每次演变都是为了低耦合,易维护的目的,但也不是一成不变,多种混合也是可以同时存在, 所以我们需要抓住每个理念的核心概念,选择合适的方式应用到工程中理解会更深!

    参考文献:https://blog.nodejitsu.com/scaling-isomorphic-javascript-code/

    一、MVC

    MVCMVC

    由屏幕获取响应指令, View 传送指令到 Controller,Controller 完成业务逻辑后,要求Model 改变状态Model 将新的数据发送到 View,用户得到反馈

    MVCViewController.m

    #import "MVCViewController.h"
    #import "MVCView.h"
    #import "MVCModel.h"
    @interface MVCViewController ()<MVCDelegate>
    
    @end
    @implementation MVCViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        MVCView *view = [[MVCView alloc]initWithFrame:[UIScreen mainScreen].bounds];
        view.delegate = self;
        
        MVCModel *model = [MVCModel new];
        
        model.name = @"name1";
        
        [view setViewWithModel:model];
        
    }
    #pragma mark - delegate
    //代理来返回view对viewController的操控
    -(void)clickChange{
        
        NSLog(@"chang  from View!");
    }
    
    

    二、 MVP

    MVP 模式将 Controller 改换为 Presenter,同时断开View和Model之间联系,通过Presenter做桥梁来沟通。


    ** MVP**** MVP**
    1. 各部分之间的通信,都是双向的。
    2. View 与 Model 不发生联系,都通过 Presenter 传递。
    3. View 非常薄,不部署任何业务逻辑,称为"被动视图"(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。
    4. Presenter 可以另一种理解为View和Model的管家

    MVPViewController.m

    #import "MVPViewController.h"
    #import "MVPPresenter.h"
    #import "MVPCell.h"
    #import "MVPModel.h"
    
    @implementation MVPViewController
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        self.view.backgroundColor = [UIColor whiteColor];
        
        MVPPresenter *present = [MVPPresenter new];
        MVPCell *view = [MVPCell new];
        MVPModel *model = [MVPModel new];
        
        //获取数据
        model.name = @"name1";
        
        //视图布局
        [self.view addSubview:view];
        
        //交给presenter处理 ,避免 view和 model 之间的交互
        [present setPreModel:model];
        [present setPreView:view];
    }
    
    
    
    

    MVPPresenter .h /.m

    #import <Foundation/Foundation.h>
    #import "MVPModel.h"
    #import "MVPCell.h"
    @interface MVPPresenter : NSObject 
    @property(nonatomic,strong)MVPCell *MVPView;
    @property(nonatomic,strong)MVPModel *model;
    
    -(void)setPreView:(MVPCell *)view;
    -(void)setPreModel:(MVPModel *)model;
    
    -(void)clickChangName;
    
    
    #import "MVPPresenter.h"
    @implementation MVPPresenter
    - (instancetype)init
    {
        self = [super init];
        if (self) {
    
        }
        return self;
    }
    
    -(void)setPreModel:(MVPModel *)model{
        self.model = model;
    }
    
    -(void)setPreView:(MVPCell *)view{
        self.MVPView = view;
        [self.MVPView setlabel:_model.name];
    }
    
    -(void)clickChangName{
        
        NSLog(@"name change %d",arc4random()%10);
    
    }
    
    

    三、MVVM

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

    唯一的区别是,它采用双向绑定(data-binding):View <->ViewModel , ViewModel作为Model中值得的映射,是数据发生改变时,通知View中发生改变 ,以后不需要考虑View和Model 之间的交互更新,只需着手界面布局逻辑即可

    MVVMViewController.m

    #import "MVVMViewController.h"
    #import "MVVMView.h"
    #import "MVVMModel.h"
    #import "MVVMViewModel.h"
    @interface MVVMViewController ()
    
    @end
    
    @implementation MVVMViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        
        MVVMView *MView = [MVVMView new];
        
        MVVMModel *model = [MVVMModel new];
        model.name = @"name1";
        MVVMViewModel *viewModel = [MVVMViewModel new];
        
        [self.view addSubview:MView];
        
        //* viewModel 作为枢纽 沟通view和model之间关系
        [viewModel setWithModel:model];
        [MView setWithViewMoel:viewModel];
    }
    
    

    关键点:

    1. 将viewModel 中nameStr与Model 中name相对应;
    2. View中label的text值将与nameStr进行绑定(KVO键值观察)
    3. 这样model的值发生改变时 ,View会自动发生改变
    4. View 和Model通过ViewModel实现动态关联

    **MVVMModel **

    #import <Foundation/Foundation.h>
    
    @interface MVVMModel : NSObject
    @property(nonatomic,copy)NSString *name;
    
    @end
    

    MVVMViewModel.h

    #import "MVVMModel.h"
    @interface MVVMViewModel : NSObject
    //对应Model中name
    @property(nonatomic,copy)NSString *nameStr;
    
    @property(nonatomic,strong)MVVMModel *model;
    
    -(void)setWithModel:(MVVMModel *)model;
    -(void)clickChangeName;
    
    

    MVVMView.m 利用KVO监测值变化

    #import "MVVMView.h"
    #import "NSObject+FBKVOController.h"
    @interface MVVMView ()
    
    @property(nonatomic,strong)MVVMViewModel *vm;
    @property(nonatomic,strong)UILabel *label;
    @property(nonatomic,strong)UIButton *button;
    
    @end
    @implementation MVVMView
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            self.backgroundColor = [UIColor whiteColor];
            self.frame = [UIScreen mainScreen].bounds;
            
            self.label = [[UILabel alloc]initWithFrame:CGRectMake(150,100 , 100, 30)];
            self.label.backgroundColor = [UIColor orangeColor];
            [self addSubview:_label];
            
            self.button = [UIButton new];
            _button.backgroundColor = [UIColor redColor];
            [_button setTitle:@"点击" forState:UIControlStateNormal];
            [_button addTarget:self action:@selector(mvvmClickChangModel) forControlEvents:UIControlEventTouchUpInside];
            _button.frame = CGRectMake(150, 200, 50, 50);
            [self addSubview:_button];
        }
        return self;
    }
    -(void)setWithViewMoel:(MVVMViewModel *)vm{
        self.vm = vm;
        //KVO
        [self.vm addObserver:self forKeyPath:@"nameStr" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
        self.label.text = vm.nameStr;
    
    //  //* FBKVO 第三方库
    //  [self.KVOController observe:self.vm keyPath:@"nameStr" options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew block:^(id  _Nullable observer, id  _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
    //      self.label.text = change[NSKeyValueChangeNewKey];
    //  }];
    
    }
    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:   (NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
        if ([keyPath isEqualToString:@"nameStr"]&&[change objectForKey:NSKeyValueChangeNewKey]) {
            NSNumber *new = [change objectForKey:NSKeyValueChangeNewKey];
            self.label.text = [NSString stringWithFormat:@"%@",new];
        }
    }
    -(void)mvvmClickChangModel{
        [self.vm clickChangeName];
    }
    -(void)dealloc{
        [self.vm removeObserver:self forKeyPath:@"nameStr"];
    }
    

    Example Demo

    GitHub : https://github.com/one-tea/MVC-MVP-MVVM.git

    相关文章

      网友评论

      • genius1108:文章写的不错,很简单易懂,让人很容易就体会到mvvm的概念了。不像别人,为了写文章而写文章。
        你的GitHub下载的demo不能用,我copy了一个出来,可以吗?
        随便,补个地址。http://download.csdn.net/download/geniuskkbb/10104054
        _方丈:@genius11088 谢谢,可以,收获分享
      • 云画的跃光:demo解压不了,说是档名太长,额?咋回事?
        云画的跃光:@OneTea 好了,用了别的解压软件,用系统自带的就不行
        云画的跃光:@OneTea 还是不行,解压不了
        _方丈:@云画的跃光 重新下载试试
      • 谢谢生活:这个mvvm感觉很怪异
        谢谢生活:MVVM VM和View的绑定是你那样吗?双向绑定 吗? 谢谢
        谢谢生活:@OneTea 兄弟 你的Demo 还是解压不了 其他软件都换了两个 看来使不得行了。
        _方丈:@谢谢生活 三种模式的简单比较,具体看需求情况而定

      本文标题:MVC/MVP/MVVM 三种设计模式简介附demo

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