<!–markdown–>转自知乎的评论,对目前流行的mvc,mvp,mvvm等开发模型作了很好的阐述。个人觉得很精彩
原文出处:http://www.cnblogs.com/indream/p/3602348.html –完整有图哦
我个人认为摩尔定律是不足以让一个敲命令行的时代在几十年间转变成这种各类框架技术架构实践模式的时代,真正推动计算机形成自有的工程学体系的是还有两样东西就是:
- 人的能力并没有变强,至少没有在同级数下变强。
- 人类一定会物尽其用
<p><!–more–></p>
因为人的能力并没有“跟上”机器,所以才会出现各种模式、方法、工具等等来补足人的不足,以最大地透支机器性能。就像我前几天在闪存无聊时突然想到的一句: 架构是对客观不足的妥协,规范是对主观不足的妥协。
<P>当我们需要机器做的事情多了起来,我们就没办法在一个芯片上解决所有事情,所以才会有冯诺依曼模型、计算机架构,没办法用一台机器解决,所以才要互联网、分布式、云计算。</P>
<P>同样,随着计算机的发展,要做的事情多了,就出现了软件的概念。当“开发”正式化,我们需求的软件就变得:功能繁杂、管理统一、多入口。</P>
<P>真正变化的不是客观本质,而是需求。就像这里说的“软件入口”在客观上我们还是只有一个,原理上始终都只有一个启动程序、一个启动代码片段。但“软件的入口”,已经从指代Main函数变成了指代起始UI,用户已经从指代专业人士变成了指代一般消费者,先有软件的需求,才有软件的定义,而需求是在变化的。</P>
一个软件需要比当时多几个数量级的代码:
- 客观上我们没办法做一个能显示所有代码的显示器
- 主观上我们没办法在超快速滚动中看清所有代码
所以我们需要添加索引、用多个文件组织代码。
<P>机器的发展和软件的需求扩大和细化,我们开始出现了用户界面(User Interface)的概念和最适合用于界面的语言——标记语言(Markup Language)。当然,ML不是为UI而生的,它只是十分适合UI,所以才和UI坠入爱河。</P>
<P>因为有了更高UI的需求,所以代码才正式被分化为描述做什么(业务逻辑)和有什么(UI)的两部分,因为我们开发时没办法在两种思维方式下同时工作,开发时的人脑是单线程的。我们所看到的同时进行UI和逻辑开发只不过是我们学会了在两种模式下快速切换,看起来像同时进行,而不是真正的同时进行。同样的情况也发生在不同的代码片段的开发中。</P>
分化的情况除了UI,还发生在方方面面,比如数据操作、UI的对象和样式分离
#事务,以及界面、数据、事件、业务
<P>在之前说到过了,当需求变得庞大,解决方案也会变得庞大;当解决方案变得庞大,就会出现细分;当出现细分,就会出现按哪种方式管理的问题。</P>
<P>软件从处理一件事务发展到了要处理许多事务,各事务间有包含、顺序、主次等等的关系,变得越来越复杂。因为数据与逻辑庞大了,所以数据与逻辑就分离了,然后事件和业务分离了。</P>
它们的关系已经在我们还理得清之前持续发展而变得更加难理得清,但在一个时间点上,它们UI的领域大致分化成这些原子:
- 界面
- 数据
- 事件
- 业务
你要细化的话会有更多繁杂的细节,但相信这么写的话争议性比较小。
<P>当一个问题出现一次的时候它是一个问题,当一个问题出现了无数次的时候它会成为历史,当一个问题将会出现无数次的时候,它将需要一个明确的定义和解决方案。</P>
<P>其中,数据的更新和界面的更新这一特殊事件的问题被放大了无数倍,因为它出现了无数次。</P>
<P>在ASP还在奋斗的时候WebForm突然到来,正如WebForm还在奋斗的时候MVC突然到来。当然,我这里讲的MVC还是最原始的MVC,因为MVC在我们还在争论的时候已经发展了许多不同分支了。</P>
<P>有一点相信大家同意的就是,我们今天讨论争论的MVC、MVP、MVVM、Code Behind等等都源自于职能分化和规划的思想与目的,MVC不是它们的开始,但是一个很好的开始。</P>
<P>相信MVC的模型大家很熟悉,也很容易找到</P>
<P>界面被分到了View,数据分到了载体Model上由Model“携带”,业务集中在Controller中,而推动业务的事件由用户与View交互,通过View向Controller发动。</P>
<P>当然,实现由很多种,每种细节上都有不同,所以我才只讲也只能讲大致的MVC。MVC的其中一个缺点便是没有明确的定义,所以不同的实现(比如Struts和http://ASP.NET MVC)细节上都是不一样的。</P>
<P>我们需要知道的是,MVC并不是像上面所说的一些事情那样是一种“必然的”结果,它是一系列必然结果问题中的一种解决方案,而且是不完美的解决方案。我们顺着推理去到一个地方很容易犯的一个错误就是认为路只有这一条而忽视其他可能性(估计这也是导致很多争斗的原因)。另外,我们在讨论一件事物不完美的时候是有一个情境的,所以请不要像“我说它色彩单一,然后你把它涂成彩色后证明我是错的”。</P>
<P>MVC的一般流程是这样的:View(界面)触发事件–》Controller(业务)处理了业务,然后触发了数据更新–》不知道谁更新了Model的数据–》Model(带着数据)回到了View–》View更新数据
这里也不多再陈述MVC的原理、实践等等,因为这就太长篇大论了。</P>
#Model-View-Presenter和一些衍生
<P>像我们之前推理的,分化是一种需求的必然结果,但却没有个一个确定的结果,比如Code Behind和Code Block的问题等等。</P>
<P>MVC顺着需求把UI相关的工作分化成了三份,这点经过实践证明无可厚非。但是它们的三角关系却被一些人认为带来了一些问题,或者应该说他们有“更好的”解决方案。</P>
<P>在只有Code Behind和Code Block的那个时候维护是很直接的,不是在同一段代码内解决就是在同一个关联的事件上解决。三角关系的问题就是维护问题。在MVC,当你有变化的时候你需要同时维护三个对象和三个交互,这显然让事情复杂化了。</P>
<P>我们之前说到,随着摩尔定律,软件的需求不断地变化和变得庞大。随着需求变得庞大的时候,需求变化也变得频繁,这是一个出现了无数次以后也将会出现无数的无数次的一个问题,所以它需要一个解决方案,哪怕它不一定能被解决。</P>
<P>对MVC的改进的思想却是一样的:切断的View和Model的联系,让View只和Presenter(原Controller)交互,减少在需求变化中需要维护的对象的数量。</P>
这种方式很符合我们的期待,因为我们倾向于:
- 用更低的成本解决问题
- 用更容易理解的方式解决问题
<P>许多时候并不是一种模式不好,而是因为人没办法执行,比如不容易理解,我们就会选择容易理解的方式。计算机依赖摩尔定律用数量的增长来解决问题,而人是用方式的改变来解决问题的。同样因为客观原因我们不善于维护多个对象和多个对象之间的关系,所以我们改变了,或者说简化了这种方式。</P>
<P>MVP定义了Presenter和View之间的接口,让一些可以根据已有的接口协议去各自分别独立开发,以此去解决界面需求变化频繁的问题。上面两图都有接口,不过接口的实现和使用细节不一样,不过思想上是一致的。</P>
<P>在这里要提到的是,事实上,需求变化最频繁的并不一定是最接近用户的界面,但基本可以确定的是,最接近用户的界面是因为需求变化而需要最频繁更改的。当然,如果View如果是API而不是UI,那就另说了。</P>
<P>还有一些用来“解决”MVC这项缺点的比如有:http://ASP.NET MVC的ViewBag,Cocoa的delegate。它们都为了简化数据更新的问题而存在,包括MVVM。</P>
#Model-View-ViewModel
先直接看看Model-View-ViewModel(MVVM)的图:
<P>从图上看是比MVP简单了,更不用说MVC了。个人不认为MVVM是从MVP进化而来,我只觉得这是在MVP之后出现的一种“更好的”UI模式解决方案,但是用MVP来与之对比比较容易说明问题。</P>
<P>ViewModel大致上就是MVP的Presenter和MVC的Controller了,而View和ViewModel间没有了MVP的界面接口,而是直接交互,用数据“绑定”的形式让数据更新的事件不需要开发人员手动去编写特殊用例,而是自动地双向同步。数据绑定你可以认为是Observer模式或者是Publish/Subscribe模式,原理都是为了用一种统一的集中的方式实现频繁需要被实现的数据更新问题。</P>
<P>比起MVP,MVVM不仅简化了业务与界面的依赖关系,还优化了数据频繁更新的解决方案,甚至可以说提供了一种有效的解决模式。</P>
至此,我们能理解为什么许多人认为MVVM是最好的一种模式,没有之一。但事实上,MVVM也是依赖于我们至今所讲的“特有的情境”。<P>
<P>当然,最优雅的也是第一个能作代表的实践就是Windows Presentation Foundation(WPF)了。</P>
#Web
<P>之上,我们在模式演变的推论基本上都还是基于桌面软件的,但是过去十年却是互联网的时代。实际上大部分让大家争议的并不是在桌面领域最合适的是那个,而是在Web领域的模式问题,也就是在B/S场景下的问题。</P>
<P>当软件离开单机,去到网络的时候,因为场景变了,所以原有的解决方案也变了,不过需求依然是不变的。我们依然要解决的问题是用户交互与数据更新的问题,还有维护等等的问题。</P>
<P>当场景变到Web的时候,我们发现MVVM用来做服务端是极其不适用的,至少现在是不适用的。而MVP你提都不用提。为什么呢?因为:
- 网络资源成本过高
- 开发成本过高
</P>
<P>问大家一个问题,当一个网页的数据更新后,你希望更新用户看到的数据,你会怎么做?</P>
一般情况下,你会:
window.location.reload();
就算你不这么做,用户也会:
F5
<P>就像之前说的,我们会选择更直接的方式解决问题。直接刷新页面的原因是因为这样更直接,更容易解决数据更新的问题。</P>
<P>很多时候你不会愿意为了一个数据更新写一个AJAX,更别说这个AJAX要带来Loading、事件顺序处理、网络问题、异常处理等等,这就是开发成本过高。</P>
<P>另一个网络成本过高就更容易解释了,虽然宽带是基本包月的,但也不带这么用的,何况还有移动用户。更主要的原因是,在本地软件,更新数据是一个引用问题,而在网络应用上,这是一个传输问题。传输成本远高于引用成本,引用之上顶多是在本地内存中再进行一次内存拷贝。</P>
<P>这个时候,我们会更倾向于用MVC模式,因为在Web层面,我们更倾向于一次性更新数据。</P>
#Web的MVVM
<P>所有问题都不是问题,就算有问题也要解决问题。</P>
<P>为什么这个标题下突然冒出这么一句话?我想说的是,需求依旧是不变的,是推动进步的原动力。
还有我之前说过,当我们讨论或者争论一个问题的时候,问题的对象已经发生改变了,而且这次是在我们讨论这个问题之前已经发生改变了。</P>
<P>网络资源成本不断下降,相信已经不需要多提及。摩尔定律和相近的一些原理正在发挥着它应用的作用,网络带宽越来越高、相应速度越来越快。</P>
<P>如果传输因为相对成本下降而导致数据传输的成本低于开发人员拒绝客户的成本,那么它就会被实现而不是被拒绝。</P>
<P>另外还有一点就是因为技术的进步,技术的资源不断被更大规模地压榨,需求也不断地增长,那么需求始终会增长超过相对不变的开发成本的。比如jQuery的出现解决了很多问题,我们现在更多地去使用AJAX,哪怕很大一部分依然是为了解决网络资源不足的问题;我们会用更多的样式代码而用了相对更少的图片;我们不再那么依赖Flash一类的矢量图解决方案而直接录制视频。</P>
<P>至少上一节我们说到的两个导致大家选用MVC的问题都正在被解决,所以我们有理由相信未来Web不仅仅需要MVC,可能会需要MVVM或其他解决方案。至少我们能理解容易理解为什么前端会出现一些MVVM的框架,比如先驱knockout.js和AngularJs。</P>