zoukankan      html  css  js  c++  java
  • 实例说明MVC,MVP,MVVM架构

    很早就知道有这三个概念,但是一直都不清楚是怎么回事,在网上搜索,都是泛泛而谈,没有具体例子,新手是看不懂的,直到找到这篇文章,我对这三个架构有了更清楚的了解。

    从一个简单的例子去研究这三个架构。

    注意,MVC,MVP,MVVM中的C,P,VM,下文都要controller指代。

    需求如下

    界面上显示100,以及两个按钮,其中一个点一下加1,另外一个点一下减1

    如图

    诚然,这么简单的需求,并不需要用什么架构去完成,可是如果是复杂的需求,要长篇大论才能说完,所以只拿简单的来做例子,实际开发中,你在完成一个需求之前,是需要好好掂量是否要用架构,要的话,用什么架构(不局限于这三个),架构里面又要用什么设计模式等等。经过我的实践,发现,即使是架构改变了,view是可以完全不变的,所以先展现view层的代码。

    html部分

    <span id="text">100</span>
    <button id="upBtn">up</button>
    <button id="downBtn">down</button>

    js部分

    function $(id) {
      return document.querySelector(`#${id}`);
    }
    function View(controller) {
      const upBtn = $('upBtn');
      const downBtn = $('downBtn');
      const textSpan = $('text');
    
      this.render = function(model) {
        textSpan.innerHTML = model.getValue();
      }
      upBtn.onclick = controller.up;
      downBtn.onclick = controller.down;
    }

    render方法是核心,方法名称不能改(后面要依赖这个render方法),其中要实现数据的展示逻辑,然后是一些点击事件的绑定

    MVC

    model层

    function Model() {
      let value = 100;
      this.up = function() {
        value += 1;
      };
      this.down = function() {
        value -= 1;
      };
      this.getValue = function() {
        return value;
      };
    }

    保存数据,并提供访问,修改数据的方法,如果仅仅是这样,那么当model改变时,view是不知道的,所以需要让model去通知view,我数据改变了,你要更新了。怎么做呢?利用观察者模式。在model中,增加一个数组views,去保存这个model对应的视图,在修改数据的时候,遍历views数组,调用每个view的render方法,参数是自己。

    修改后的model

    function Model() {
      let value = 100;
      const self = this;
      const views = [];
      this.up = function() {
        value += 1;
      };
      this.down = function() {
        value -= 1;
      };
      this.getValue = function() {
        return value;
      };
      this.broadcast = function() {
        views.forEach(view => view.render(self));
      };
      this.subscribe = function(cb) {
        views.push(cb);
      }
    }

    仔细看修改后的model,虽然增加了通知的方法(broadcast),但是在修改数据的方法(up和down)中并没有去通知视图。这个工作是由controller承担的,另外把view注册到model中,也是controller做的。

    controller层

    function Controller() {
      let view = null;
      let model = null;
      this.up = function() {
        // 修改数据
        model.up();
        // 通知视图
        model.broadcast();
      };
      this.down = function() {
        model.down();
        model.broadcast();
      }
      this.init = function() {
        view = new View(this);
        model = new Model();
        // 把视图注册到model中
        model.subscribe(view);
      }
    }

    可以看到,controller把自己传给了view去创建视图,同时保存引用,创建model后,把view注册到model中。同时实现了,改变数据,通知视图的工作。

    请一定要好好理解MVC,后面的MVP,MVVM都只是稍加修改而已。

    MVP

    在MVC中,改变数据,通知视图,都是在controller做的,注册视图,以及通知视图,这两个方法的实现,都是model完成的,既然model负责数据处理,这两个工作实际上和改变数据是没关系的,把他们都转移到controller中,不仅可以让model层专注于数据处理,同时也方便多个视图共用一个controller

    model层

    function Model() {
      let value = 100;
      this.up = function() {
        value += 1;
      };
      this.down = function() {
        value -= 1;
      };
      this.getValue = function() {
        return value;
      };
    }

    model层更小了,删除了注册,通知方法,只保存数据和提供获取,修改数据的方法

    controller层

    function Controller() {
      let views = [];
      let model = null;
      function broadcast() {
        views.forEach(view => view.render(model));
      }
      this.up = function() {
        model.up();
        broadcast();
      };
      this.down = function() {
        model.down();
        broadcast();
      }
      this.init = function() {
        views.push(new View(this));
        model = new Model();
      }
    }

    controller,增加了广播方法,该方法的实现和调用都在controller中,另外,如果想多个视图共用一个controller,如果这多个视图都是同一个model,上面代码能够胜任,如果是这多个视图是不同的model,那就要自己去实现好view和model的对应关系了(要用map来存储对应关系,一个数组做不到)。

    MVVM

    可以看到,在MVP中,model也有一个up方法,controller也有一个up方法,只是增加了一个广播方法的调用。是不是有些重复呢?把这两个类似的方法整合到controller,model只负责保存数据,不实现修改数据的逻辑,这就是MVVM了,极大地精简model

    model层

    function Model() {
      let value = 100;
      this.getValue = function() {
        return value;
      };
      this.setValue = function(v) {
        value = v;
      }
    }

    其实,不用函数,单纯地用一个变量,也是可以的,但是为了view层不变,view层中依赖model的getValue方法,所以这里还是用函数去实现model

    controller层

    function Controller() {
      let views = [];
      let model = null;
      function broadcast() {
        views.forEach(view => view.render(model));
      }
      this.up = function() {
        model.setValue(model.getValue() + 1);
        broadcast();
      };
      this.down = function() {
        model.setValue(model.getValue() - 1);
        broadcast();
      }
      this.init = function() {
        views.push(new View(this));
        model = new Model();
      }
    }

    精简model的代价是controller要做更多的事情,实现修改数据的逻辑,通知视图。如果用框架,react或者vue,通知视图这部分框架会帮你实现,只要实现数据修改的逻辑就好了。

    至此,三个架构都讲完了,如果错误,欢迎讨论。

    代码可在github上下载,需要node环境。

    参考资料:http://www.cnblogs.com/zhouyangla/p/6936455.html

  • 相关阅读:
    Linux 中如何用源代码安装软件,以及如何卸载它
    Linux 中的 Install命令
    PHP 常用header头定义
    如何防止重复提交表单?
    如何从二维数组中的多个key中获取指定key的值?
    jquery的ajax全局事件详解
    PHP+MySQL分页显示示例分析
    javascript中的事件类型
    事件委托/事件代理,
    彻底弄懂JS的事件冒泡和事件捕获
  • 原文地址:https://www.cnblogs.com/maoscut/p/7623462.html
Copyright © 2011-2022 走看看