MVC演化史
Martin Fowler在他所写的《企业应用架构模式》一书中感慨道:MVC已经成为我们最常误用的模式。人们之所以常常误用MVC,很大程度上是因为混淆了不同的MVC变体。
Classic MVC
大概上世纪七十年代,Trygve在Xerox PARC提出了MVC的概念,并应用在Smalltalk系统中,为了和其它类型的MVC加以区分,历史上习惯的称之为Classic MVC。
注意:从依赖关系看,Model不依赖View和Controller,而View和Controller依赖Model。
Classic MVC关注两个分离:
从Model中分离View,主要基于以下几点考虑:
从View中分离Controller就不那么重要了。Desktop软件的时代,View和Controller往往是一一对应的关系,所以常常把他们合并成为UI,事实上,当时多数UI框架都没有实现从View中分离Controller。后来随着Web的兴起,这种分离(模板技术)才开始流行起来。
本质上Classic MVC的结构如下图所示,之所以说本质上,是因为View和Controller其实是彼此关联的,但这种关联和稍后提到的MVP完全不同,更像是一种框架的副产品,为了避免引起混淆,这里省略了它们,具体参阅:How to use Model-View-Controller (MVC)
图解:Controller截获用户通过鼠标或键盘发出的请求,然后改变Model的状态,Model通过Observer Synchronization通知View自己的状态发生了变化,View查询Model展现数据。
Classic MVC并不完美,不适用于复杂的逻辑。举个例子:用户通过鼠标拖动滚动条来调整音量大小,如果音量大于某个数值,背景色变红以示提醒。当使用Classic MVC的时候,如何处理背景色变红的逻辑呢?有两个选择:
Application Model MVC
大概上世纪八十年代,ParcPlace从Xerox Parc划分出来,负责Smalltalk的研发工作,为了适应更复杂的逻辑,开发了Classic MVC的改进版,也就是Application Model MVC,在原有架构基础上引入了Application Model,如下图所示:
图解:Application Model在Model和View、Controller之间扮演着一个中继者的角色。
接着看前面的例子,既然Model和View都不适合放背景色变红的逻辑,那么我们可以尝试把相关逻辑放在Application Model中实现,当用户通过鼠标调整音量大小时,Model触发一个普通事件,Application Model拦截到这个事件,判断音量是否大于临界值,如果是就触发一个特殊事件,View收到后完成相关逻辑的处理。
Application Model MVC虽然看似解决了复杂逻辑的问题,但它仍然存在硬伤:
首先随着以微软视窗为主的图形化操作系统的兴起,操作系统本身提供了一套原生的View接口,用来截获用户通过鼠标或键盘发出的请求,结果让Controller显得多余了。
其次由于在Application Model MVC中,View的渲染只能通过事件的方式实现,Application Model不能直接操作View,所以某些情况下不能方便的实现业务逻辑。接着前面说的调节音量的例子,这次我们加个新功能,不再通过鼠标拖动滚动条来调整音量大小,而是给出一个文本框,让用户直接通过键盘输入阿拉伯数字表示音量大小,一旦用户输入非法内容(比如说英文字符,标点符号),背景色变黄以示警告。问题是如果用户输入非法内容,就不应该改变Model的状态,但不改变Model的状态,View就没有机会收到渲染的事件。
MVP
大概上世纪九十年代,IBM的Mike Potel提出了MVP的概念。与此同时,Smalltalk团队正在开发新一代框架,当他们看到MVP时,发现它不仅和MVC非常相似,并且很好的解决了复杂逻辑的问题,所以决定使用它,出于复杂度的关系,他们简化了MVP:
图解:View截获用户请求,然后委派给Presenter,Presenter改变Model的状态,Model通过Observer Synchronization通知View自己的状态发生了变化,View查询Model展现数据。
最重要的是一点是Presenter和View彼此持有对方的引用。实际解决问题时有点像足球比赛时的二过一配合。虽然View截获用户请求,但它并不处理,而是委派给Presenter处理,所以保证了可测试性,同时,因为Presenter可以直接操作View,不必受限于观察者模式。
接着前面说的调节音量的例子,当用户通过鼠标拖动滚动条来调整音量大小时,View截获请求,并把请求委派给Presenter,如果Presenter发现音量大于临界值,直接操作View实现逻辑;当用户通过键盘输入音量大小时,View截获请求,并把请求委派给Presenter,如果Presenter发现内容非法,直接操作View实现逻辑。
Martin Fowler分析了MVP的实现方式,分类为Supervising Controller和Passive View。
二者的区别在于Model和View是否有联系,在Supervising Controller的实现中,View可以查询Model,Model状态发生变化的话会通知View,而在Passive View的实现中,View不可以查询Model,Model状态发生变化的话会通知Presenter,由Presenter完成View的渲染。比较而言,Passive View的可测试性更好一些,但其Presenter的代码量也会增加不少。
…
前面我们讨论了MVC到MVP的演化史,随着Web的兴起,人们开始把MVC,MVP等知识应用到Web环境下,但Web环境有其特殊性,最重要的一点就是HTTP是无状态的,每次请求都是独立的,所以不可能实现观察者模式。
Web MVC
Java是Web MVC最早的实践者,开发出Model 2,使用JavaBean,JSP,Servlet分别对应MVC中的三个组成部分,紧接着Structs的出现开始让大众注意到Web MVC,不过真正让Web MVC流行起来的却是Ruby社区的Rails,其大致流程如下图所示:
图解:Controller截获Browser请求,查询Model,Model查询Database后把数据返回给Controller,Controller在把数据传递给View,View渲染完成后发送给Brower。
在MVC中,Controler可以改变Model的状态,View可以查询Model的状态,所以说对Model而言,Controller和View的地位是平等的,不过在Web MVC中,Controller变成了中继者,协调Model和View,如此看来,Web MVC中的Controller等同于MVP中的Presenter。那为什么不叫Web MVP,而称之为Web MVC?这是因为截获请求的是Controller而不是View。
花絮:Python社区的Django框架宣称自己使用的是MTV,其实质仍然是Web MVC。
Web MVP
在Desktop的时代,微软通过WinForms实现MVP,把组件化编程发挥到了极致,大大提升了开发效率,随着Web的兴起,微软希望延续这样的编程模式,所以使用WebForms实现了Web MVP,但由于MVP并不适应无状态的HTTP环境,所以微软不得不引入ViewState的概念,用以模拟状态的存在。结果造成了Web MVP虽然可以非常快捷的开发一些中小项目,但却不适合大项目的要求,也正因为如此,微软又开始向Web MVC发展。
图解:微软Web MVP vs Web MVC。注意入口是Controller还是View!
…
最后以C2上的一句话结尾:We need SMART Models, THIN Controllers, and DUMB Views
说明:本文使用了下列链接中的内容:
建议继续学习:
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:老王 来源: 火丁笔记
- 标签: MVC 演化
- 发布时间:2011-05-03 23:39:30
- [4000] QR码分析
- [72] Twitter/微博客的学习摘要
- [69] Go Reflect 性能
- [68] Oracle MTS模式下 进程地址与会话信
- [67] IOS安全–浅谈关于IOS加固的几种方法
- [67] 【社会化设计】自我(self)部分――欢迎区
- [63] 如何拿下简短的域名
- [63] 图书馆的世界纪录
- [63] 流程管理与用户研究
- [62] find命令的一点注意事项