浅谈MV*模式

最近想总结一下前端中的MV*(MVC、MVP、MVVM)模式。

但是,鉴于自己的理解还是比较局限,我想在此转Livoras的一篇博客。

本文对这篇博客的观点比较赞同,并且引用了该文章的图片。大家可以不必展开我的文章,直接读这一篇大作。

原文链接:界面之下:还原真实的MV*模式

注:本文有图,但是由于网络原因,图片未能上传,后续补上。?

<!–more–>

MV*模式解决什么问题

简而言之,我认为MV*就是实现了领域模型数据和UI层的解耦。

但是MVC、MVP、MVVM对其解耦的思路的不同。从历史的角度来看,MVC、MVP和MVVM是一种进化的关系。但是鉴于项目的规模以及模式实现的方式不同,不同的MV*模式各有其优点和缺点,难分孰好孰坏。

但是业界越来越认为:MVVM是前端领域最好的MV*模式。

下面我就分别谈一下这三种模式。

MVC模式

MVC模式的应用程序,除了有UI层(View)和领域模型(Model)之外,多加了一层Controller。他们之间的关系是这样的:

用户对View的输入等操作并不会在View的相关模块中处理逻辑,而是由Controller层获得这些操作(所谓的Pass Call),并由Controller层对这些操作中的数据经过应用逻辑的操作,然后在调用Model层的接口,将数据交给Model层。Model层执行与业务逻辑相关的操作,并更新数据。Model和View通过观察者模式联系在一起,即View是Model的观察者,当Model数据变动之后,通知View层进行数据更新。

我们看到MVC是一个单向的三角关系。

总的来说:

  1. Model主要是与业务数据有关。

  2. View是应用程序数据的可视化表示。

  3. Controller管理应用程序中Model和View之间的逻辑和协调。

  4. View了解Controller,Controller了解Model,而View能够直接访问Model。

MVP模式

MVP比起MVC模式,它的特点很明显。MVP中M和V之间的依赖关系被消除了。

在MVC中,M和V之间通过观察者模式依赖。这种依赖关系在MVP中被转移到M和P层中。这样一来P层必须通过一定的机制通知V层进行数据的更新。所以MVP模式中V层中提供了供P层调用的接口。P层作为观察者获得数据变化是,将调用V层的接口将变化反映到V层中。

总的来说,MVP中:

  1. Model层依然是主要与业务数据有关。

  2. View依然是应用程序的可视化表示,但是在MVP中它对领域数据(Model层)完全无知,比起MVC中View层更轻了。

  3. Presenter层比较重,它不仅调用Model的接口,也调用View的接口。而且需要作为观察者获得Model的数据更新。

MVVM模式

最后来看下MVVM模式:

MVVM模式中,M层数据的变化不是通过观察者模式通知到V层的(即没有M和V的依赖),也不是通过VM层调用V层的接口将数据传递给V层的(这意味着用户代码不需要手动更新V层)。而是通过在VM层实现一个特殊的binder,将数据从M层直接绑定到V层。这样ViewModel层了解Model层,View层了解ViewModel层。

ViewModel充当了一个数据转换器的作用。它将Model信息转换为View信息,还将命令从View传递到Model。在这里,View可以访问ViewModel,ViewModel可以访问Model。

我理解的ViewModel是:

  1. ViewModel为View提供了一个访问Model的桥梁,但是View不是直接访问Model层。ViewModel为View提供了Model的特定于View的子集,可以包含状态和逻辑信息,而且无需向View暴露整个Model。

  2. View和ViewModel通过数据绑定和事件可以进行通信,因为ViewModel可以访问Model层,所以ViewModel为了数据绑定要暴露Model中的部分属性。

关于业务逻辑,很多前端框架都单独做了一个与MVVM无关的Service层,将业务逻辑放到Service层中,由ViewModel调用。即:View => ViewModel => Service这样一个流向。

对于双向绑定《界面之下》是这么描述的:

双向数据绑定。可以简单而不恰当地理解为一个模版引擎,但是会根据数据变更实时渲染。

其实我不是很确定这样理解对不对。

不过双向绑定带来了一个缺点,那就是数据绑定的声明是指令式地写在View的模版当中的,这些内容是没办法去打断点debug的。

一个很浅显的困惑

吐个槽而已

MVC、MVVM等高大上的词汇,从我开始接触web开发的时候就不绝于耳。开始使用ExtJS4.2的时候,“大神”告诉我这是一个实现了MVC模式的框架。然后还很耐心的告诉我:MVC有三层,它们分别放在不同的文件夹下。这个XX.view.js实现了View层,这个XX.Model.js实现了Model层,这个XX.controller.js实现了Controller层。

后来,我开始对Vue.js感兴趣。我告诉“大神”说这是个MVVM模式的框架。他也很兴奋,指着我的代码兴冲冲的问我:你写这些个东西,哪个是Model呢?我也被问蒙了,对啊,Model在哪呢?

直到我不再跟着“大神”干活之后,我才发现,那些话都是狗屁。

(我没有说谁坏话的意思。也可能是我对他的话有误解,所以才造成了我现在的困惑。)

MV*框架和用户代码

诚然,框架帮我们实现了MV*模式,不代表我们写的代码也是按照MV*模式组织的。因为我们使用了框架,本身就意味着我们认同它的架构和模式,然后调用框架的API,来实现业务层代码。因此即使用户代码中出现类似vm,view等等的命名,也不代表这段代码就是MV*中某一层的实现,而更像是对某一层的实现的一个扩展。而且不同的模式下的用户代码量级确实有时会有显著差距。

再总结以下三点:

  • MV*模式的框架 + 用户代码 约== MV*模式的软件

  • MV*模式的框架,是MV*模式的一个实现。

  • 模式提供的通用解决方案,其记录方式并不与某个特定问题挂钩(《JavaScript设计模式》, O’RELLY出版)。

结束

最后再吐槽一下:《JavaScript设计模式》这本书,翻译的真心不太好,我真的读不通顺。

一点微小的见解,多多指正。

完。

    原文作者:samchowgo
    原文地址: https://segmentfault.com/a/1190000006145707
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞