MVC,MVP 和 MVVM 的图示

作者: 阮一峰

日期: 2015年2月 1日

复杂的软件必须有清晰合理的架构,否则无法开发和维护。

MVC(Model-View-Controller)是最常见的软件架构之一,业界有着广泛应用。它本身很容易理解,但是要讲清楚,它与衍生的 MVP 和 MVVM 架构的区别就不容易了。

昨天晚上,我读了《Scaling Isomorphic Javascript Code》,突然意识到,它们的区别非常简单。我用几段话,就可以说清。

(题图:摄于瓦伦西亚,西班牙,2014年8月)

一、MVC

MVC模式的意思是,软件可以分成三个部分。

  • 视图(View):用户界面。
  • 控制器(Controller):业务逻辑
  • 模型(Model):数据保存

各部分之间的通信方式如下。

  1. View 传送指令到 Controller
  2. Controller 完成业务逻辑后,要求 Model 改变状态
  3. Model 将新的数据发送到 View,用户得到反馈

所有通信都是单向的。

二、互动模式

接受用户指令时,MVC 可以分成两种方式。一种是通过 View 接受指令,传递给 Controller。

另一种是直接通过controller接受指令。

三、实例:Backbone

实际项目往往采用更灵活的方式,以 Backbone.js 为例。

1. 用户可以向 View 发送指令(DOM 事件),再由 View 直接要求 Model 改变状态。

2. 用户也可以直接向 Controller 发送指令(改变 URL 触发 hashChange 事件),再由 Controller 发送给 View。

3. Controller 非常薄,只起到路由的作用,而 View 非常厚,业务逻辑都部署在 View。所以,Backbone 索性取消了 Controller,只保留一个 Router(路由器) 。

四、MVP

MVP 模式将 Controller 改名为 Presenter,同时改变了通信方向。

1. 各部分之间的通信,都是双向的。

2. View 与 Model 不发生联系,都通过 Presenter 传递。

3. View 非常薄,不部署任何业务逻辑,称为"被动视图"(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。

五、MVVM

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

唯一的区别是,它采用双向绑定(data-binding):View的变动,自动反映在 ViewModel,反之亦然。AngularEmber 都采用这种模式。

(完)

珠峰培训

简寻

留言(55条)

原来我一直做的是MVP呀

很好。写的不错。

这么说来 Django 好像是一个 MVP 框架的样子了…

MVC是单向的?不是V->C->M -> C -> V 吗?

清晰易懂

简明,真知灼见;不像市面上很多文章那般说一揉二,掺杂一起弄得复杂方显高深,骨架连肉一起乱炖,反致初学者云里雾里。

跟马老师说的不一样,阮老师确定吗?
附上:
PoEAA - http://martinfowler.com/eaaCatalog/modelViewController.html
MSDN - https://msdn.microsoft.com/en-us/library/ff649643.aspx

看这篇文章可能更容易理解:http://objccn.io/issue-13-1/

要是再谈谈最近流行的 flux react 就好了

引用dreamers.yzy的发言:

MVC是单向的?不是V->C->M -> C -> V 吗?

同问,有点不是很理解为什么是单向的呢?

引用dreamers.yzy的发言:

MVC是单向的?不是V->C->M -> C -> V 吗?

我所了解到的情况也是v-c-m-c-v这个流程。。

在微博你纯属测试为知笔记功能 @mywiz,打开为知笔记果然看到了,看完了之后来这里顶一下。

正好这三个模式我都认识,^_^。我是自学 Rails 的,Rails 就是 MVC 的,刚开始学 Rails 时,把逻辑都放进了 Views 里,虽然 Rails 提供了 Helper,但是感觉不 OO,就没用。后来发现 Views 逻辑太多了,而想对网站外观进行修改时就很费力,放进 Model 中的话,在 Model 中生成 URL 等就很复杂了,需要包含各种 Rails Helper。后来发现了 Github 上的 Presenter,就是把不知道该放进 View 还是 Model 的东西放进去,View 中不再与 Model 交互,今天才知道这叫 MVP。MVVM 是我看的 Rails 作者的一篇文章中写得,英文不好,当时看个大概,没怎么明白,今天才明白了。 >_

MVC在bs架构和cs架构上差别很大,即使同是bs,因为使用的技术的差别,业务的差别,架构的差别,MVC的通信方式也会和原来你书本上看到的不一样。就像backbonejs和angularjs的出现,是发明还是延伸,还是糟蹋?每天和它一起工作的人才知道。
所有的设计应该以贴近自然或接近自然规律为目标。再通俗的讲,用的舒服就是自然。好的东西绝对不需要强记一堆原理来理解的。

引用end-e的发言:

我所了解到的情况也是v-c-m-c-v这个流程。。

是的,我理解的MVC也是这个流程的……

iOS开发中大部分使用的MVC和阮兄说的MVP一样... 有些人也会做成MVVM

这里的MVP, MVVM甚至MXXX都只是MVC的变体而已,至于将重点放在C点还是V点(没人会希望放到M点吧?!)就自然引出了若干种所谓的模式,其实模式只有一种,你称为P也好VM也好,它都只是C的实例而已。总是设法弄出一些所谓的Business Word的家伙们,是前端开发最大的敌人!

引用KILLVIN_LIU的发言:

这里的MVP, MVVM甚至MXXX都只是MVC的变体而已,至于将重点放在C点还是V点(没人会希望放到M点吧?!)就自然引出了若干种所谓的模式,其实模式只有一种,你称为P也好VM也好,它都只是C的实例而已。总是设法弄出一些所谓的Business Word的家伙们,是前端开发最大的敌人!

真的不一样... 虽然同源, 但是实践起来效果是不一样的... 简洁清晰高效的构架不是程序员的毕生追求吗?

写得很好。另外提一句,我是计算机背景,老程序员了,对于那些说什么你错误很多,我可以负责任地说,把自己的理解和想法写出来,你比大多数人水平高很多了,但肯定有些不完善的地方,大家可以讨论一起进步,这是重点,因为你没有错误很多!

觉得无法理解“双向绑定”和“相互通信”,这两个的最终效果其实是一样的吗?

引用andong777的发言:

是的,我理解的MVC也是这个流程的……

看来很多人 MVC才是最难解 呵呵

『唯一的区别是,它采用双向绑定(data-binding):View的变动,自动反映在 ViewModel,反之亦然』
——>难道不是:Model的变动,自动反映在 ViewModel 吗?

我是搞web后台的,我对MVC的理解是:

M=数据对象+数据访问+业务逻辑,必要时可以分层

C=路由+视图逻辑

V=视图,如果是接口开发这层可以不要

Fat model, thin controller

是不是不同的软件对MVC的理解不同?

这个是不同领域不一样的,阮兄这说的应该只是前端领域,不然会造成误解。对于后端以及ios等其他领域都是不适用的。

只能说都用过,理解还是不到位

MVVM 中的view是绑定了viewmodel的命令了的,所以我觉得MVVM的view也应该指向viewmodel

引用andong777的发言:

是的,我理解的MVC也是这个流程的……

我理解的也是这种情况。

从现在类似angularjs这种Model才能直接影响view。。

在java中的MVC,应该就是我们理解的这个V->C->M->C->V

引用那谁的发言:

我是搞web后台的,我对MVC的理解是:
M=数据对象+数据访问+业务逻辑,必要时可以分层
C=路由+视图逻辑
V=视图,如果是接口开发这层可以不要
Fat model, thin controller
是不是不同的软件对MVC的理解不同?

我比较认同你的看法。不过博主这篇说的是前端mvc,跟后端还是有很大区别的。 顺便说一句,阮老师对于前端框架的很多观点都是不妥当的,建议看看寒冬那篇 UI架构设计的演化

对MVC的理解偏差很大.
M,V之间是Observer模式,即V直接依赖M,M间接依赖V.M,C之间是C直接依赖M.这两点是MVC中最广泛认可,同时也是MVC成为一个解决方案模式的关键:视图和逻辑分离.

理想的MVC模式中V,C之间没有直接依赖(没有单向依赖),但现实中做不到.Native应用要一般由view分发事件给controller,controller要决定那些view用户可见.

Web应用中情况好一点.用户可以直接通过url直接访问controller,不需要view知道controller,但是controller还负责路由view.前端复杂化后,页面上与controller交互更频繁,controller也很难只通过url来实现了.

事实上MVC有三个问题:
1.V和M之间不匹配,用户界面和流程要考虑易用性,用户体验优化同时考虑业务流程的精确和无错.
2.C和M之间界线不清,什么样的逻辑是界面逻辑,什么样的逻辑是业务逻辑,很难定义清楚.
3.V的变化不能完全由Model控制,即observer模式不足以支持复杂的用户交互.这其实要求VC之间要有依赖.

后来的MVP与MVVM都是为了优化V,C之间的关系而提出的.
MVP认为VC之间强绑定不可避免, 但可以加强P的能力,V变成只显示,P提供数据给V,把双向依赖简化为P直接依赖于V.
由于V的数据由P提供,则MV之间的Observer关系转移到MP之间.

MVP主要解决1,3两个问题,但代价是加重了问题2.P更重,而且与Model耦合无法框架化.但实践中view很难完全被动
化,它总是会随用户的事件变化,这部分成为P的负担.

而MVVM则是另一个方面来解决问题.MVVM认为view应该是事件驱动,模型变化只是一种事件.C应该只处理view与模型不
配合的问题,而问题3可以通过分离用户交互与界面构造.C退化为一个View的模型VM,它与view之间由框架提供事件-
数据的绑定.

MVVM与MVP相比主要彻底解决了问题1,重新定义了问题2,在MVVM中VM的功能比较明确,把M翻译成View需要的数据.
VM有一定视图的属性,view与VM有对应关系,也就解决一部分问题3.但是由于各角色职责已经定义,需要引入第四个
组件来解决这个问题.

我们可以打个分,直接依赖计为1,间接依赖计为0.5
全部互相依赖是6
理想MVC,MV=1.5,MC=1共2.5
现实MVC根据VC之间的依赖情况可能是0.5到2,实际是3到4.5
MVP,MP=1.5,VP=1,MV=0共2.5与理想情况一致.
MVVM,MVM=1.5,VM+V=0.5或1,共2到2.5,即不高于理想MVC

标题改为『前端框架MVC,MVP 和 MVVM 的图示』似乎更加妥当

你好,个人觉得MVC中C应该程序的流转,非业务处理

avalon.js也是一个MVVM的javascript框架

引用anthony的发言:

对MVC的理解偏差很大.
M,V之间是Observer模式,即V直接依赖M,M间接依赖V.M,C之间是C直接依赖M.这两点是MVC中最广泛认可,同时也是MVC成为一个解决方案模式的关键:视图和逻辑分离……


感谢分享,我觉得您的补充十分必要。

引用ChenKan的发言:

标题改为『前端框架MVC,MVP 和 MVVM 的图示』似乎更加妥当

几个不同的意见。
如 ChenKan 所言,请网友注意,阮兄此文主要讲到前端的 MVC 和相关模式的讨论。

1. 作者提到 MVC 的两种流,但举出 Backbone.js 的例子却全然不符合这两种例子中的任何一种。因为 Backbone.js 本来是更强调 View逻辑——是 View逻辑,不是 View。View逻辑即 Presenter。因此 Backbone.js 本质上是一种 MVP 模式。之所以有 Router,因为它本来就是一种 Route:没有这些 Route,一个 RIA APP 一样工作的很正常;Route 虽然看起来也有 C 的作用,但它更重要的是导航功能,在它里面对 render view 的调用本来就是反模式,事实证明在 View 的 initialize 中调用一样合适,参考此文章中的论述:https://lostechies.com/derickbailey/2011/12/23/backbone-js-is-not-an-mvc-framework/。
2. 我认为阮兄说的两种 MVC 流程是错误的。(1) Model 无法将数据“发送”给 View,因为它根本不知道 View 的存在,数据应该是由 Controller 持有,并显示出 View。 (2) 因此,用户也不是直接操作 Controller,即使是输入 URL,也可以认为那是由 View 触发的(就像在 View 上点击了一个链接)。
因此,MVC 的处理流程是 V -> C -> M -> C -> V。
3. MVP 模式实际上就是 MVC,只不过这里面的 C 主要负责的不再是业务逻辑,而是界面逻辑了,比如何时显示/隐藏某个选项卡,绑定 View 事件等。
4. 我们现在在讨论的 MVC 与经典的 MVC 略有不同,经典的 MVC 里,C 是应用控制器,包括路由的概念;而现代软件 UI 层的 C 通常仅包含界面相关逻辑的处理。
5. 对于 MVVM 的模式,确实在 B/S 和 C/S 界有不同理解,这一点值得提醒。

(对上面那篇略作完善,还请阮兄帮我删除上面那篇评论,非常感谢。)

难道我把MVP理解成了MVC?

我想,从楼上(s)的讨论中,我得到了一些启发。但具体在coding时要怎么用,要用什么,是要看具体情况而定的;而且随着人类思维的开阔,将来可能会有更好的模式。所以,不用太纠结。先会用,能用好就可以。不是嘛?

引用goldli的发言:

我想,从楼上(s)的讨论中,我得到了一些启发。但具体在coding时要怎么用,要用什么,是要看具体情况而定的;而且随着人类思维的开阔,将来可能会有更好的模式。所以,不用太纠结。先会用,能用好就可以。不是嘛?

说的很对。
本来是想了解这几个的区别的,结果查了半天,越看越晕。其实领悟了模式的精髓,能用好就行,至于叫什么并不重要

Comparison of Architecture presentation patterns MVP(SC),MVP(PV),PM,MVVM and MVC
http://www.codeproject.com/Articles/66585/Comparison-of-Architecture-presentation-patterns-M

引用那谁的发言:

我是搞web后台的,我对MVC的理解是:
M=数据对象+数据访问+业务逻辑,必要时可以分层
C=路由+视图逻辑
V=视图,如果是接口开发这层可以不要
Fat model, thin controller
是不是不同的软件对MVC的理解不同?

赞同,MVC(mvc mvp mvvm)就是路演成了你理解的这样,责权分明。过去整个web开发比较容易发现的混乱想象就是:视图与逻辑混杂在一起,视图(应用)逻辑与业务逻辑混杂在一起。

@陈计节:

赞同对MVC模式的修正2(1),在移动Native应用中同样如此,Model和View需要尽可能的分离
2(2)也有类似想法web中URL实际上也是在操作view,只不过这个view是浏览器本身(本人3年前从web开发转到移动前端开发)
对于3.MVP,@ anthony讲的非常明白。P相当于业务逻辑+界面逻辑

看到书的广告了,买了本书看看

mvc原则上model是不与view层交互的吧,model广义上讲不是单单的数据封装而是承载了明确的业务逻辑处理,当然可能只是简单的网络或数据库存取。controller负责接受用户交互指令,后对model进行访问,之后组装成view,相当于model与view之前的桥梁所以称之为控制器。
之所以让model层负责更多的业务,主要原因是遍于重构,代码复用,在一个view层经常变更的场景下,controller相应的也会变,但因为业务层独立,可以保证做到最少的代码变更。
上面提到的是经典的web、app开发,至于现在的前端web mvc,以ember来说,我对它对controller的定义觉得区别于上面的,更像是某种新的模式或反模式。

好文章

MVP里,View可以直接访问model,View不能直接访问model的是Application Model架构

Application Model: Views hand off events to the presenter as they do to the application model. However the view may update itself directly from the domain model, the presenter doesn't act as a Presentation Model. Furthermore the presenter is welcome to directly access widgets for behaviors that don't fit into the Observer Synchronization.

详见:http://martinfowler.com/eaaDev/uiArchs.html

引用justNode的发言:

我比较认同你的看法。不过博主这篇说的是前端mvc,跟后端还是有很大区别的。 顺便说一句,阮老师对于前端框架的很多观点都是不妥当的,建议看看寒冬那篇 UI架构设计的演化

做开发三四年了,前段、后端和IOS客户端都有过一些开发经验,而且也经常和团队里的其他成员交流开发心得。综合来看,大家对MVC的模型、视图、控制器的概念都是一致的,只是由于在前后端和客户端不同的开发场景下,有不同的侧重点而已。
比如前端主要是页面展示和用户交互,因此MVC中重点在视图V,有些场景下承担业务逻辑和交互的控制器C与视图V完全放在了一起,而模型M即与服务端交互的接口及浏览器本地的存储操作则作为单独的一部分;后端开发就会有很大不同,尤其是只提供接口时,MVC中就会更侧重模型M,视图V概念则弱化为了对外开放的接口具体到实现上甚至就是一系列的接口列表,而控制器C则承担接口的实现及部分服务端操作如定时任务等功能,成为较厚重的一层,模型M承担数据库操作和从其他服务获取数据的功能则作为第三层;客户端的MVC则一般都较为均衡,但是界面展示与业务逻辑很多时候还是会强绑定,造成V与C结合在一起,例如纯代码开发IOS时,每个页面的展示及交互逻辑分层很明显,但是就整个项目来说,视图V并没有形成单独的一层,是成为了控制器C层的一部分。
因而,MVC也好,MVP也好,MVVM也好,重要的是针对应用场景和需求对M、V、C三层进行划分,三层间的交互也是如此。只要确定了架构后遵循一定的原则,在开发过程中尽量不破坏原有规则,直到现有的架构规则不能满足需求,再重新制定。这样应该就能在满足应用场景需求的同时,使得项目有明确清晰的层次。在比较框架的定义和优劣时,也要有一定的场景说明才有实际意义。
回到阮老师的总结,个人感觉他是从广义上对这些框架进行讲解的,我们在理解时,应该根据不同项目的实际情况进行参照。大家在评论的时候最好说明是在什么样的场景下框架的使用,这样也方便不同开发背景的同学学习。

谁跟你说的MVC是单向的?
Model能直接操作View?Model是禁止操作View!
Controller就不能操作View?Controller就是Model那取到数据再去操作View

引用Sinksfish的发言:

谁跟你说的MVC是单向的?
Model能直接操作View?Model是禁止操作View!
Controller就不能操作View?Controller就是Model那取到数据再去操作View

对啊我也是这样认为的

这样理解的话,我觉得区分MVC与其他的区别是不是View和Model能不能直接通信,至于是单向还是双向我倒是觉得是不是跟具体的业务有关?个人拙见,当然阮老师写的相当清楚明白,谢谢

我这两天也特地去查mvc相关知识,得到的点是:
1. 经典MVC设计是给非web系统的,
2. MVC web框架其实不是真正的MVC设计模式,而是JSP Model2设计模式。

参考:
http://stackoverflow.com/questions/1931335/what-is-mvc-in-ruby-on-rails
http://www.sitepoint.com/getting-started-with-mvc/
https://www.wikiwand.com/en/JSP_model_2_architecture

MVC的那个图错了吧…m与v并不会直接交互

一派胡言。作者你懂mvc 吗????model 和 view永远不可以有任何直接联系。此乃mvc的最大忌讳。居然你一开头开始就扯淡。

1. Web 的 MVC,Model 不知道 View 的存在
2. 而 Swing 等的 MVC,View 里放了 Model(例如 JTable 里有 TableModel),Model 数据变化时触发事件,View 会收到这个事件触发更新操作

非常棒的讲解, 对于新人很有帮助~! 谢谢博主~~~!

mvc 模式讲错了,阮老师,view发送指令给controller,controlle接受指令通知model层操作数据,接着返回controller层,controller再渲染view。

MVC 的 C 怎么回事业务逻辑呢?

我要发表看法

«-必填

«-必填,不公开

«-我信任你,不会填写广告链接