0
点赞
收藏
分享

微信扫一扫

关于 MVVM和MVC的一些总结

SPEIKE 2022-12-12 阅读 164


我的需求:

  • 晚上练完车之后,之前参考我毕设的一个小伙伴要答辩,问了我一个问题,结果问的一下不知道怎么回答…​​以下是我回答他问题的答案​​:所以在回答完他之后,赶快整理一波…

我需要解决的问题:

  • MVVM到底是个什么东东,和前后端有没有关系,它和MVC区别是啥,有啥优势。

我是这样做的:

  • ​百度​​寻找,找了一些关于MVVM论文,博客,梳理出自己的答案。
  • 嗯,资源比较零散,准确性有待考量,所以不对的地方请小伙伴指出来

爱自己,是终生浪漫的开始 ------王尔德

对于MVC想来小伙伴是不陌生的,但是网上的资源各抒己见…我也整的晕头转向的,可能有​​前(后)端​​​,有​​胖(瘦)客户端​​框架应用,具体还有细微的差异。

If you put ten software architects into a room and have them discuss what the Model-View-Controller pattern is, you will end up with twelve different opinions. --Josh Smith​​1​​
如果你把10个软件架构师放在一个房间里,让他们讨论模型-视图-控制器模式是什么,你最终会得到12种不同的观点。

我们这里讨论的​MVC​​和​​MVVM​​​是以​​BS架构​​​为基础的​​java Web​​​中的应用,因为博主只接触了这方面的,关于网上提到的​​IOS​​​和一些​​客户端​​​框架,没有接触过。本博客也不涉及。所以如果听都没听过​​java Web​​​的,或者没了解过 ​​Web框架​​的小伙伴个人感觉这篇博客不太适合,不太建议继续读下去。

我们先看看MVVM吧!嘻嘻 ^ _ ^

MVVM 名词解释:

​MVVM​​​是​​Model-View-ViewModel​​​的简写。它本质上就是​​MVC​​​的改进版。MVVM 就是将其中的​​View的状态和行为抽象化​​​,让我们将​​视图 UI​​​和​​业务逻辑​​​分开。当然这些事​​ViewModel​​​已经帮我们做了,它可以取出 ​​Model​​​ 的数据同时帮忙处理​​View​​​中由于需要展示内容而涉及的业务逻辑。​​MVVM(Model-View-ViewModel)框架​​​的由来便是​​MVP(Model-View-Presenter)模式​​​与​​WPF​​​结合的应用方式时发展演变过来的一种​​新型架构框架​​​。它立足于原有​​MVP​​​框架并且把​​WPF​​的新特性糅合进去,以应对客户日益复杂的需求变化。​2​​

​MVVM​​​upright=1.5 ​​MVVM(Model–view–viewmodel)​​​是一种​​软件架构模式​​​。 ​​MVVM​​​有助于将​​图形用户界面的开发​​​与​​business logic​​​(业务逻辑)或​​后端逻辑​​​(数据模型)的开发​​分离​​​开来,这是通过置标语言或GUI代码实现的。MVVM的视图模型是一个​​值转换器​​​, 这意味着​​视图模型​​​负责从​​模型​​​中​​暴露(转换)数据对象​​​,以便轻​​松管理和呈现对象​​​。在这方面,​​视图模型​​​比​​视图​​​做得更多,并且处理大部分​​视图​​​的​​显示逻辑​​​。 视图模型可以实现​​中介者模式​​,组织对视图所支持的用例集(Model)的后端逻辑的访问。 ​3​​

MVVM 的发展历程

​MVVM​​​是​​马丁·福勒​​​的​​PM(Presentation Model)设计模式​​​的变体。​​MVVM​​​以相同的方式​​抽象​​​出​​视图的状态和行为​​​, 但​​PM​​​以​​不依赖于特定用户界面平台​​​的方式抽象出​​视图​​​(建立了视图模型)。 ​​MVVM​​​和​​PM​​​都来自​​MVC模式​​​。 ​​MVVM​​​由微软架构师​​Ken Cooper​​​和​​Ted Peters​​​开发,通过利用​​WPF(微软.NET图形系统)​​​和​​Silverlight(WPF的互联网应用衍生品)​​​的特性来​​简化用户界面​​​的​​事件驱动程式设计​​​。 微软的WPF和Silverlight架构师之一​​John Gossman​​​于​​2005​​​年在他的博客上发表了​​MVVM​​​。 MVVM也被称为​​model-view-binder​​​,特别是在不涉及​​.NET平台​​​的实现中。ZK(Java写的一个Web应用框架)和KnockoutJS(一个JavaScript库)使用​​model-view-binder​​。​3​​

MVC到MVVM 的发展历程

二十世纪八十年代​​施乐帕克实验室​​​提出了​​MVC​​​的概念,MVC的全称即​​Model-View-Controller​​​,是​​模型(model)​​​一​​视图(view)​​​一​​控制器(controller)​​​的缩写“…,它是一种​​客户端软件开发框架​​​4​​​,个人认为,其实最初的​​Java Web​​​来讲,​​Model2​​​ 即​​Servlet+JSP​​​也是用的这个结构,所以说​​Model2(MVC)​​​它相对已​​Model1(Javabean+JSP)​​​来讲,已经实现了​​View​​​和​​Model​​的部分解耦,但是不彻底,如图

关于 MVVM和MVC的一些总结_软件架构


​view​​​负责显示,​​Model​​​负责提供数据,​​Controller​​负责逻辑的处理,其实现的流程大概是:​4​​

  • (1)当用户需要发送请求时,首先是在View发送请求,由View将指令传送到Controller里。
  • (2)Controller接收到指令之后,先完成所需要的业务逻辑,然后要求Model根据业务逻辑改变状态;
  • (3)Model将新的数据发送给View,View则根据新的数据更新视图,从而用户的请求得到反馈。

在​​MVC​​​框架中,​​View​​​是可以直接访问​​Model​​​的(JSP里直接使用​​JavaBean​​​),这样不可避免的使​​View​​​里面也需要包括一些​​业务逻辑​​​,同时还需要​​Model​​​保持不变,而​​Model​​​又对应着多个不同的显示(View),所以总体说来就是,在MVC模型里面,​​Model​​​不依赖​​View​​​,但是​​View​​​是依赖于​​Model​​​的。这样就导致更改​​View​​​比较困难,且​​业务无法重用​​​。从而​​MVC框架的弊端就显现出来​​​4​​​,这也是使用​​Servlet+JSP​​​的弊端。前后端没有解耦,​​Model​​​与​​View​​没有彻底解耦。

为了解决​MVC​​框架中​​View​​​和​​Model​​​联系紧密的问题,开发者研究开发了​​MVP​​​模式,​​MVP​​​即​​Model-View-Presenter​​​,即把MVC中的​​Controller​​​换成了​​Presenter​​​,目的就是为了完全切断​​View​​​跟​​Model​​​之间的联系,在MVP模式中,​​View​​​负责​​视图的显示​​​,​​Model​​​负责​​提供数据​​​,​​Presenter​​​则主要负责​​逻辑业务​​的处理。​4​​

有些​SSM+JSP​​的开发方式也是基于这种,我之前的公司就这样写,前后端不分离使用的​​JSP​​​,但是交互全是​​Ajax​​​,传递的全是​​JSON​​​,也没有返回​​ModelAndView​​​,个人感觉这里其实是使用了​​MVP​​​的模式。以前后端​​不分离​​​的方式​​丢弃模板引擎的服务端渲染​​​,追求前后端​​分离​​​中​​彻底解耦了View和Model​​​。看上去怪怪的,其实有时候项目开发更多的是和​​业务​​​、​​体量​​​、​​成本​​​、​​效益​​​等有关系,综合考虑,选最合适,不一定要按照​​常规​​​的​​构建方式​​​考虑,比如正常思考可能​​不分离​​​是为了​​服务端渲染​​​,​​首屏快载​​​,​​SEO​​​等,分离是为了​​降低服务器压力​​​,​​接口复用​​​,前后端​​工作职责解耦​​.

对于​​SSM​​​+​​模板引擎​​的开发方式

  • 如何是返回​​Modelandview​​​的话,那​​缺点​​​就是​​后端路由​​​,前后端没有​​彻底解耦​​​,优点就是​​服务端渲染​​​,返回的是整个​​构建好的页面​​.
  • 如果返回​​JSON​​​的话,那优点就是​​前后端彻底解耦​​​,​​接口复用​​​,但是没有利用模板引擎的​​服务端渲染​​。
  • 如果体量很大,那前后端是两个人写,那使用​​Modelandview​​​的方式就很麻烦,需要​​接口协调​​​,而且工作​​职责不清晰​​。会浪费好多时间。JSON就方便很多。
  • 如果体量不是他大,前端的东西也不是特别多,考虑成本问题,前后端一个人写,那​​Modelandview​​就很合适,节省了接口协调,对接等时间成本问题。

关于 MVVM和MVC的一些总结_mvvm_02


在​​MVP​​​框架中,​​View​​​无法直接再与​​Model​​​交互,​​View​​​和​​Model​​​之间的通信都是通过​​Presenter​​​进行完成的,所有的交互都在​​Presenter​​​内部发生,即由​​Presenter​​​充当了​​View​​​和​​Model​​​的桥梁,做到​​View-Model​​​之间通信的​​完全隔离​​​。​​Presenter​​​完全把​​Model​​​和​​View​​进行分离,将主要的程序逻辑放在Presenter里实现。​4​​

Presenter​​与​​View​​​也是没有直接相关联的,而是通过已定义的​​接口进行交互​​​,从而使得在变更​​View​​​的时候可以保持​​Presenter​​​的不变,即保证了​​Presenter​​​的可重用性(接口的复用性),同时也解决了​​MVC​​​框架中的​​View​​​和​​Model​​关联紧密的问题。​4​​

这样之后,对于​​Web​​​项目来讲,前后端都是通过数据进行交互,那​​路由​​​怎么处理,前端只能实现简单一部分跳转,涉及到复杂的需要​​通过Controller(Presenter)来处理的路由​​​怎么处理,或者带状态的路由如何跳转,即​​Controller无法控制使用那个View​​​。个人感觉,​​Web​​​系统来讲这个时候​​完全的前后端分离​​​可能不是适合所有项目,而且分离之后留给​​前端要解决的问题​​可能也不是能很好的解决。所以这个时候…

有个叫​​Rod Johnson​​​带领一帮人搞出的​​SpringMVC​​​,不像桌面应用的​​MVC​​, 这里的Model没法给View 发通知。​5​​​也不像​​MVP​​​, 这里的​​Controller​​​可以控制​​View​​​来实现路由。即前后后端没有分离,但是将原来的​​View的构建解耦​​​了。由​​模板​​​和​​数据​​构成:

public class MyGlobalException {
@ExceptionHandler(MaxUploadSizeExceededException.class)
public ModelAndView customException(MaxUploadSizeExceededException e) {
ModelAndView mv = new ModelAndView("javaboy");
mv.addObject("error", e.getMessage());
return mv;
}
}

即降低了​​View​​​和​​Model​​​耦合,同时又实现了​​后端路由​​。

关于 MVVM和MVC的一些总结_MVVM_03


对于大型项目而言,​​前端​​​的东西原来越多,造成​​服务端​​​的压力越来越大,而且由于​​MVP​​​的出现,逐渐向​​前后端分离​​​靠拢,分离之后,View分担​​服务端​​​的压力,或者说是​​浏览器​​​分担了​​服务器​​压力,包括页面渲染,路由等问题,这时侯MVVM出现了…(这里是自己猜的,没找到相关资料

​MVVM​​​框架便是​​前后端分离框架发展史​​​上的一次思想的完全变革。它是将​​数据模型双向绑定​​​的思想作为变革的​​核心​​​,即​​View​​​的变动,自动反映在​​ViewModel​​​上面,而​​ViewModel​​​的变动也会随即反映在​​View​​​上面,从而实现​​数据与模型的双向绑定​​。​4​​

在​​MVVM​​​框架中,​​View​​​用于发送用户的​​交互请求​​​,之后将用户请求转交给​​ViewModel​​​,​​ViewModel​​​即可根据用户请求操作​​Model​​​数据更新,待​​Model​​​数据更新完毕,便会通知​​ViewModel​​​数据发生了变化,然后​​ViewModel​​​就会即刻更新​​View​​数据,完成视图的更新,从而完成用户的请求。​4​​​

关于 MVVM和MVC的一些总结_mvc_04

虽然​​MVVM​​​框架和之前的​​MVC​​​、​​MVP​​​模式的目的相同,即完成​​视图(View)和模型(Model)的分离​​,但它却有着明显的优势。​4​​

  • 首先,MVVM框架中的​​View​​​完全可以独立于​​Model​​​发生​​变化和修改​​​,彻底解耦,View发生变化时Model可以不变,同样,当Model发生变化时View也可以不变化,并且一个​​ViewModel​​​可以绑定到多个不同的​​View​​​上面,这就体现了​​MVVM框架的低耦合性​​。
  • 其次,绑定在一个​​ViewModel​​​上面的多个​​View​​​都可以使用​​ViewModel​​​里面的视图逻辑,完成了框架可重用性的特性。除此之外,​​MVVM框架​​​还具有​​可独立开发​​​、​​可测试​​等特性,把框架作用发挥到最大化,也因此成为了开发者们青睐的框架。。

对于​​MVVM​​​这种模式主要用于构建​​基于事件驱动的 UI 平台​​​,对于前端开发领域中​​数据与界面相混合​​的情况特别适用​6​​,其中

  • ​Model​​​ 仅仅只是代表应用程序所需的数据信息,它​​不关注​​任何行为;
  • ​View​​​ 是软件中与用户进行直接交互的部分,它需要响应 ​​ViewModel​​​ 的事件并格式化数据,​​不负责​​控制应用的状态;
  • ​ViewModel​​​ 用于​​封装业务逻辑层​​​,这点类似于 MVC 模式中的控制器,它​​控制View​​​的很多显示逻辑,它可以把​​数据模型​​​的变化​​传递​​​给​​视图​​,也可以把视图中数据的变化传递给数据模型,即在 Model 和View 之间建立了双向绑定。
Vue与MVVM

我第一次看到​​MVVM​​​是因为​​Vue​​​,相信好多小伙伴也是​​Vue​​​认识​​MVVM​​​架构模式。Vue官网中讲到:虽然没有完全遵循 ​MVVM​​ 模型,但是 Vue 的设计也受到了它的启发。因此在文档中经常会使用 vm (ViewModel 的缩写) 这个变量名表示组件实例

关于 MVVM和MVC的一些总结_mvvm_05


通过​​双向数据绑定​​​连接​​视图​​​层和​​数据​​​,而实际的​​界面 UI 操作​​​(​​DOM 操作​​​)被封装成​​对应的指令​​​(Directives)和​​过滤器​​(Filters)

MVVM原理:​​7​​

实现​​数据绑定​​的做法有大致如下几种:

  • 脏值检查(angular.js): ​​angular.js​​​ 是通过​​脏值检测​​​的方式比对数据是否有​​变更​​​,来决定是否​​更新视图​​​,最简单的方式就是通过 ​​setInterval()​​​ 定时​​轮询检测​​​数据变动,angular只有在指定的​​事件触发时​​​进入​​脏值检测​​.
  • ​DOM​​​事件,譬如用户输入文本,点击按钮等。( ​​ng-click​​)
  • ​XHR​​​响应事件 (​​$http​​ )
  • 浏览器​​Location​​​变更事件 ( ​​$location​​ )
  • ​Timer​​​事件​​( $timeout , $interval )​
  • 执行 ​​$digest()​​​ 或 ​​$apply()​
  • 数据劫持(vue.js):​​数据劫持​​​,指的是在​​访问​​​或者​​修改​​​对象的某个属性时,通过一段代码​​拦截​​​这个行为,进行​​额外的操作​​​或者​​修改返回结果​​​。简单地说,就是当我们​​触发函数​​​的时候 动一些手脚做点我们自己想做的事情,也就是所谓的 ​​"劫持"操作​

在Vue中其实就是通过​​Object.defineProperty​​​来劫持对象属性的​​setter和getter​​​操作,并“种下”一个​​监听器​​​,当数据发生变化的时候发出通知:​​Object.defineProperty(obj,prop,descriptor)​​​​参数:​​ obj:目标对象
prop:需要定义的属性或方法的名称
descriptor:目标属性所拥有的特性
​可供定义的特性列表:​​ value:属性的值
writable:如果为false,属性的值就不能被重写。
get: 一旦目标属性被访问就会调回此方法,并将此方法的运算结果返回用户。
set:一旦目标属性被赋值,就会调回此方法。
configurable:如果为false,则任何尝试删除目标属性或修改属性性以下特性(writable, configurable, enumerable)的行为将被无效化。
enumerable:是否能在for…in循环中遍历出来或在Object.keys中列举出来。

​Proxy数据代理​​​:Proxy 可以被认为是​​Object.defineProperty() 的升级版​​​。外界对​​某个对象的访问​​​,都必须经过这层​​拦截​​​。因此它是针对 整个​​对象​​​,而不是 对象的某个​​属性​​。

var data = {name:'test'}
Object.keys(data).forEach(function(key){
Object.defineProperty(data,key,{
enumerable:true,
configurable:true,
get:function(){
console.log('get');
},
set:function(newValue){
console.log('监听到数据发生了变化');
document.getElementById(‘myText’).value=newValue;
}
})
});
document.getElementById(‘myText’).addEventListener(‘keyup’,function(e){
data.name=e.target.value; // 监听 View 的变化,同步更新 Model
});
data.name //控制台会打印出 “get”
data.name = 'hxx' //控制台会打印出 "监听到数据发生了变化"

var arr = [1,2,3]
var handle = {
//target目标对象 key属性名 receiver实际接受的对象
get(target,key,receiver) {
console.log(`get ${key}`)
// Reflect相当于映射到目标对象上
return Reflect.get(target,key,receiver)
},
set(target,key,value,receiver) {
console.log(`set ${key}`)
return Reflect.set(target,key,value,receiver)
}
}
//arr要拦截的对象,handle定义拦截行为
var proxy = new Proxy(arr,handle)
proxy.push(4) //可以翻到控制台测试一下会打印出什么

  • 发布者-订阅者模式(backbone.js):

上述介绍了简单的​​一对一双向绑定​​​的实现,即一个​​数据模型​​​只与一个​​视图​​​进行绑定。当多个​​View​​​与一个 ​​Model​​​进行绑定时,每次更新 ​​Model​​​时需要在​​Model​​​ 的​​set​​​访问器属性中更新多个 ​​View​​​,这样硬编码的方式不利于​​后期的维护​​​。为了解决​​硬编码带来的耦合性过强​​​的问题,在在实际实现中,需要使用到设计模式中的​​发布 - 订阅模式​​。

​发布 - 订阅模式​​​(又称​​观察者​​​模式)是一种常用的设计模式,该模式包含​​发布者​​​和​​订阅者​​​两种角色。可以让​​多个订阅者​​​订阅同​​一个发布者​​​发布的主题,当发布者的主题发生变化时,对外发送一个通知,所有订阅了该主题的订阅者都会接收到更新的消息。因此,观察者模式定义的是​​一种一对多的关系​​。发布 - 订阅模式非常适合于 MVVM 双向绑定中多个视图绑定到同一个数据模型的情形。

实现双向数据绑定步骤​​7​​

要实现​​mvvm​​的双向绑定,就必须要实现以下几点:

  1. 实现一个​​指令解析器Compile​​​,对每个元素节点的指令进行扫描和解析,根据​​指令模板​​​替换数据,以及​​绑定​​​相应的​​更新函数​
  2. 实现一个​​数据监听器Observer​​​,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并​​通知订阅者(Dep)​
  3. 实现一个​​Watcher​​​,Watcher是订阅 - 发布模式中订阅者的实现,作为连接​​Observer​​​和​​Compile​​​的桥梁,能够订阅并收到每个属性变动的通知,​​执行指令​​​绑定的相应回函数 (发布),从而​​更新视图​
  4. MVVM入口函数,整合以上三者

    当​​​新建​​​一个​​Vue 对象​​​时,框架进入​​初始化​​阶段。Vue 在初始化阶段主要执行两个操作:
  • 第一个是​​遍历系统中数据​​​的所有属性,来对各个属性的​​变化添加监听​​;
  • 第二个操作是利用​​指令编译器 Compile​​​对视图中绑定的指令进行扫描​​进行视图的初始化​​​,然后订阅 ​​Watcher​​​ 来​​更新视图​​​,此时 ​​Watcher​​​ 会将自己添加到​​消息订阅器Dep​​中。至此,Vue的初始化过程结束。

在系统运行过程中,一旦系统中的数据模型发生了变化,​​观察者 Observer​​​的 setter 访问器属性就会被触发,此时消息​​订阅中心​​​ Dep 会遍历它所维护的所有​​订阅者​​​,对于每一个订阅了该数据的​​对象​​​,向它发出一个​​更新通知​​​,订阅者收到通知后就会对​​视图​​进行相应的更新。以上过程不断往复循环,这就是 MVVM 模式在 Vue.js 中的运行原理。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Two-way data-binding</title>
</head>
<body>
<div id="app">
<input type="text" v-model="text">
{{ text }}
</div>
<script>
function observe (obj, vm) {
Object.keys(obj).forEach(function (key) {
defineReactive(vm, key, obj[key]);
});
}
function defineReactive (obj, key, val) {
var dep = new Dep();
Object.defineProperty(obj, key, {
get: function () {
if (Dep.target) dep.addSub(Dep.target);
return val
},
set: function (newVal) {
if (newVal === val) return
val = newVal;
dep.notify();
}
});
}
function nodeToFragment (node, vm) {
var flag = document.createDocumentFragment();
var child;
while (child = node.firstChild) {
compile(child, vm);
flag.appendChild(child);
}
return flag;
}
function compile (node, vm) {
var reg = /\{\{(.*)\}\}/;
// 节点类型为元素
if (node.nodeType === 1) {
var attr = node.attributes;
// 解析属性
for (var i = 0; i < attr.length; i++) {
if (attr[i].nodeName == 'v-model') {
var name = attr[i].nodeValue; // 获取v-model绑定的属性名
node.addEventListener('input', function (e) {
// 给相应的data属性赋值,进而触发该属性的set方法
vm[name] = e.target.value;
});
node.value = vm[name]; // 将data的值赋给该node
node.removeAttribute('v-model');
}
}
new Watcher(vm, node, name, 'input');
}
// 节点类型为text
if (node.nodeType === 3) {
if (reg.test(node.nodeValue)) {
var name = RegExp.$1; // 获取匹配到的字符串
name = name.trim();
new Watcher(vm, node, name, 'text');
}
}
}

function Watcher (vm, node, name, nodeType) {
// this为watcher函数
Dep.target = this;
// console.log(this);
this.name = name;
this.node = node;
this.vm = vm;
this.nodeType = nodeType;
this.update();
Dep.target = null;
}
Watcher.prototype = {
update: function () {
this.get();
if (this.nodeType == 'text') {
this.node.nodeValue = this.value;
}
if (this.nodeType == 'input') {
this.node.value = this.value;
}
},
// 获取daa中的属性值
get: function () {
this.value = this.vm[this.name]; // 触发相应属性的get
}
}
function Dep () {
this.subs = []
}
Dep.prototype = {
addSub: function(sub) {
this.subs.push(sub);
},
notify: function() {
this.subs.forEach(function(sub) {
sub.update();
});
}
};
function Vue (options) {
this.data = options.data;
var data = this.data;
observe(data, this);
var id = options.el;
var dom = nodeToFragment(document.getElementById(id), this);
// 编译完成后,将dom返回到app中
document.getElementById(id).appendChild(dom);
}
var vm = new Vue({
el: 'app',
data: {
text: 'hello world'
}
});
</script>
</body>
</html>

我的理解

  • 架构意义角度(Web端的角度):​​MVC​​和​​MVVM​​在本质上都是为了​​实现View和Model的解耦​​,​​MVC​​是通过​​Controller​​实现了​​View​​和​​Model​​的​​解耦​​,一般用与客户端,或者​​Web​​端的整个架构过程;而​​MVVM​​是在​​MVC​​发展到​​MVP​​后(为了彻底解决View和Model的耦合问题),在提出​​前后端分离​​的基础上(考虑Coltroller的复用性,接口复用性),对​​View层​​进行了​​增强(Vue.js)​​,或者说细化了View层的表现手法,提出了通过​​ViewModel​​对视图层的​​View​​和​​Model​​解耦。
    个人感觉​​MVVM​​和​​MVP​​的整体​​架构​​是有​​相似​​的地方的,不同的是面对的​​问题域​​不同,​​MVP​​是​​Web​​架构整体的解决方案,​​MVVM​​主要用于构建​​基于事件驱动的 UI 平台(界面)​​,适用于​​前端​​开发领域中​​数据与界面相混合​​的情况,所以它只专注于​​视图层​​,​​抽象​​出​​视图​​的状态和行为,实现了​​用户界面的UI(View)​​和​​数据(Model)​​的​​解耦​​。这个​​View​​和​​Model​​虽然和​​MVC​​中描述的一样,但是不相同的,可以理解为​​MVC​​中​​View​​中包含了​​MVVM​​的架构方式。
    一般​​前后端分离​​的​​Web​​开发中会结合​​MVC​​和​​MVVM​​两种架构模式。使用​​MVC​​构建整体的​​Web​​架构,使用​​MVVM​​解决​​View​​层​​DOM​​和​​data​​的耦合问题。
  • 关于 MVVM和MVC的一些总结_mvc_06

  • 设计模式角度考虑 :​​MVC​​是基于​​观察者​​设计模式的,​​Model​​作为一个主题,​​View​​作为观察者,当一个​​Model​​变化时,会通知更新一个或多个依赖的​​View​​,反之;
    MVVM可以看做是基于​​中介者​​设计模式和​​观察者​​设计模式,​​View​​和​​Model​​通过​​ViewModel​​这个​​中介者对象​​进行交互,解耦了​​View​​和​​Mode​​l的同时实现​​数据双向绑定​​。
    同时​​ViewModel​​ 作为一个​​主题对象​​,​​View​​和​​Model​​为两个观察者(或者可以理解为​​View​​为主题时,​​Model​​为观察者,反之。这里的​​Model View​​起到一个​​注册​​,​​通知​​的作用,对于​​观察者​​模式的定义,​​ModelView​​是主题的行为,但实际变化的是​​View​​或者​​Model​​,个人觉得两种理解都没问题,理解不对的请小伙伴指出来),当​​Model​​变化时,​​ViewModel​​由​​数据绑定​​通知并更新与之相关的多个​​View​​,反之,当​​View​​变化时,​​ViewModel​​由​​DOM监听​​通知更新相关的多个​​Model​​。
举报

相关推荐

0 条评论