当前位置: 首页 > 科技观察

FromScripttoCodeBlocks,CodeBehindtoMVC,MVP,MVVM

时间:2023-03-17 23:41:43 科技观察

刚刚过去的周五(3-14)例行主持了一个技术会议,主题恰好是《UI层的设计模式——从Script、Code Behind到MVC、MVP、MVVM》,是前一天晚上决定的。中午准备了半个小时,然后开始讲课。今天看到大家在交流MVVMknockout.js友(ji)和good(谎),所以整理一下,更广泛地分享。主要目的不是争辩,毕竟恰好题材相近,原计划是分享和记录技术。那么我们按照大致的历史流程来划分这些概念:ScriptCodeBlocks,CodeBehindMVC,MVP,MVVM我们知道实际的历史顺序并不是上面那样,因为思路都差不多,比如MVC很早就出现了很久以前,解释型语言基本上都有很多分支,流行于网络时代。但我要说的是:不要注意这些细节!当然,这是个玩笑。我的意思是,我懒得在另一个独立的话题中讨论这些内容,篇幅有限。Script这里的脚本并不是说当时是用脚本开发的,而是像脚本一样开发的。它们都有一个特点:功能单一、管理单一、入口单一。我们最早的程序是汇编。那时,码农的工作是一份兼职。工作内容是写了一套短命的机器控制指令,有的甚至是command,比如今天还保留的Command(求亮点):后来,computers用于科学计算等等,还有需求驱动需要更高的开发效率,所以我们有了高级语言。当时,大多数编码员都是数学家。程序的功能很简单,就是进行一些数学计算,类似于今天ICPC的一些算法题,比如HelloWorld:main(){printf("hello,world\n");}这时候程序也可以归结为输入到输出的过程,我们还是可以说说冯诺依曼模型。在这个时代,开发就是编写机器指令,“开发”这个词甚至不配用来形容这项工作。Software,UI和MarkupLanguage都说UI在那个时代放屁,根本不存在这个概念。但这一切都要归功于我们的法宝——摩尔定律。但我个人认为摩尔定律还不足以在几十年内将一个敲命令的时代转变为这个各种框架技术架构实践模式的时代。真正促使计算机形成自己的工程系统的还有另外两件事。那就是:人的能力并没有变强,至少没有在同一个层次上变强。人类会物尽其用,因为人类还没有“跟上”机器,所以会出现各种模型、方法、工具等,以弥补人类的不足,最大限度地发挥机器的性能。就像前几天在闪存里无聊时突然想到的一句话:架构是对客观缺陷的妥协,规范是对主观缺陷的妥协。当我们需要机器做更多的事情的时候,我们不能在一个芯片上解决所有的事情,所以我们有了冯·诺依曼模型和计算机体系结构,机器是解决不了的,所以我们需要互联网,分布式公式,云计算。同样,随着计算机的发展,可以做的事情越来越多,出现了软件的概念。当“开发”形式化后,我们需要的软件就变成了:功能复杂、统一管理、入口多。真正改变的不是客观性,而是需要。就像这里说的“软件入口”,客观上我们还是只有一个。原则上永远只有一个启动程序和一个启动代码片段。但是,“软件入口”已经从指代Main功能变成了指代初始UI,用户也从指代专业人士变成了指代普通消费者。首先是软件需求,然后是软件定义。需求在变化。一个软件需要比当时多几个数量级的代码:客观上,我们做不出一个可以显示所有代码的显示器。主观上我们看不到超快滚动的所有代码,所以需要加索引,用多文件代码组织起来。随着机器的发展和软件需求的扩展和细化,我们开始有了用户界面(UserInterface)的概念和最适合界面的语言——标记语言(MarkupLanguage)。当然,ML不是为UI而生的,它只是非常适合UI,所以我爱上了UI。因为需要更高的UI,所以官方把代码分为两部分,分别描述做什么(业务逻辑)和拥有什么(UI),因为我们在开发的时候不能同时在两种思维方式下工作。人脑是单线程的。我们看到的同时做UI和逻辑开发无非是我们学会了非常快速地在两种模式之间切换,让我们看起来像是在同时做,而不是实际做同时。在不同代码片段的开发中也会发生同样的情况。除了UI,差异化还发生在方方面面,比如数据操作,UI对象和样式的分离,我们继续从UI说起。CodeBlock和CodeBehind(其实还有CodeInside,比如onclick="javascript:alert('Ohmy*')")UI和逻辑是用两种不同的语言写的,但是也应该放在同一个项目。因为他们注定要一起工作。即使是分开的,它们也需要连接起来,因为这就是它们要解决的问题。这时,我们出现的(通常)解决方案是CodeBlock和CodeBehind。虽然从时间上看CodeBlock早于CodeBehind,有种越新越好的感觉,但本质上是交替发展的,因为UI和逻辑代码分化后,谁也解决不了一个哲学问题——UI和逻辑走在一起,又不走在一起。CodeBlock可以很好的处理UI和逻辑的关系。您可以在同一位置维护UI和逻辑:@modelGM.OA.Finance2.Web.Models.FinancialBase.CurrencyModel@{ViewBag.Title="EditCurrencyDrawer";Layout="~/Views/Shared/_DrawerLayout.cshtml";}@sectionstyles{}添加新货币CodeBehind可以很好的处理UI和逻辑的分离。你可以让UI和逻辑做它们自己的事情:veAllCurrencies_Button"runat="server"Text="删除所有货币别"OnClick="RemoveAllCurrencies_Button_Click"/>protectedvoidRemoveSelectedCurrency_Button_Click(objectsender,EventArgse){varcurrencyId=Currencies_ListBox.SelectedItem.Value;currencyManager.Remove(currencies_Button_Click);}protectedvoidRemoveSelectedCurrency_Button_Click(objectsender,EventArgse)){currencyManager.RemoveAll();}因为有两种实现,所以有比较,因为有比较,所以有争论,就像Java和.NET,PHP和.NET,WebForm和MVC,MacOS一样和Windows,iOS和Android,腾讯和所有其他互联网公司等等。问题不是哪个更好,而是我们要解决什么问题。当然,这听起来(ben)像(lai)像(jiu)是礼貌的是的,UI和逻辑的划分带来的真正问题是:是按逻辑和UI划分管理,还是按单接口事务划分管理?相信同一个事务是基于一系列操作完成的同一个用户界面。在摩尔定律还在的时候,计算机领域还在高速发展,所以通常当我们还在为同一个事情争论、思考、争论的时候,它已经发生了质的变化,而唯一的事情就是不变是我们要解决的问题。#p#事务,还有接口、数据、事件、业务,前面已经讲过了。当需求变得庞大时,解决方案也会变得庞大;当解变大时,就会有细分;当细分发生时,就会出现如何管理的问题。该软件已经从处理一项交易发展到处理多项交易。时间等等之间的关系变得越来越复杂。因为数据和逻辑是巨大的,数据和逻辑分离,然后事件和业务分离。他们的关系在我们搞清楚之前就一直在发展,变得越来越难理解,但是在一个时间点上,他们的UI领域大致分为这几个原子:如果要细化界面数据事件业务,有细节会比较复杂,但是我相信这样写的话争议会小一些。一个问题出现一次就是问题,一个问题出现无数次就成为历史,一个问题出现无数次就需要一个明确的定义和解决方案。其中,数据更新和界面更新的特殊事件问题被放大了无数倍,因为它出现过无数次。Model-View-Controller在ASP还在挣扎的时候突然来到了WebForm,就像MVC在WebForm还在挣扎的时候突然来了一样。当然,我这里说的MVC还是最原始的MVC,因为在我们还在争论的时候,MVC已经发展出了很多不同的分支。有一点相信大家比较认同的是,我们今天讨论的MVC、MVP、MVVM、CodeBehind等等,都是出于功能差异化和规划的思想和目的。MVC不是他们的开始,但却是一个好的开始。MVC模型相信大家都很熟悉,也很容易找到。这里用一张百科上的图:我们可以看到,界面分为View,数据分为载体Model,由Model“承载”。业务集中在Controller中,推动业务的事件由用户与View交互发起,通过View发送给Controller。当然,实现有很多种,每一种在细节上都不一样,所以我只能笼统的说说MVC。MVC的缺点之一是没有明确定义,因此不同的实现(如Struts和ASP.NETMVC)有不同的细节。我们需要知道的是,MVC并不是像上面提到的一些事情那样是“必然”的结果,它是对一系列必然结果问题的解决方案,是一种不完善的解决方案。我们靠推理去一个地方很容易犯的一个错误就是认为只有一种方式而忽略了其他的可能性(估计这也是很多打架的原因)。另外,我们讨论不完美的东西是有上下文的,所以请不要说“我说它是单一颜色,然后你涂上颜色,证明我错了”。MVC的大致流程是这样的:View(接口)触发一个事件--》Controller(业务)处理业务,然后触发数据更新--》不知道是谁更新了Model的数据——》Model(带数据)返回View--》查看更新数据,这里就不说MVC的原理,做法等了,因为这个太长了。Model-View-Presenter和一些派生我们之前推理过,差异化是一个需求的必然结果,但是没有一定的结果,比如CodeBehind和CodeBlock问题。MVC把UI相关的工作沿着需求分成三部分,实践证明是可以理解的。但他们的三角关系被一些人视为问题所在,或者我应该说他们有“更好”的解决方案。在只有CodeBehind和CodeBlock的时候,维护非常简单,无论是在同一段代码内还是在同一关联事件上。三角关系的问题就是维护问题。在MVC中,当你有变化时,你需要同时维护三个对象和三个交互,这显然会使事情变得复杂。正如我们之前所说,随着摩尔定律,软件需求不断变化并变得巨大。随着需求变得巨大,需求的变化也变得频繁。这是一个出现了无数次之后又会出现无数次的问题,所以需要一个解决方案,哪怕不一定能解决。为了解决需求的变化,从《人月神话》到Agile再到DDD,不是我们已经解决的问题,而是我们正在解决的问题。在UI模式和MVC方面,就是对MVC模式进行优化或者替代,其中一种就是Model-View-Presenter(MVP)模式。再来看看MVP模式的两张图:(图一)(图二)两张图不一样,但是改进MVC的思路是一样的:切断View和Model之间的联系,让View只与Presenter(原Controller)交互,减少需求变化时需要维护的对象数量。这种方法符合我们的预期,因为我们倾向于:以更低的成本解决问题,用更容易理解的方式解决问题。很多时候,并不是一个模型不好,而是人无法实现,比如不容易理解,我们就会选择容易理解的方式。计算机依靠摩尔定律解决问题的方式是数量的增加,而人类解决问题的方式是方法的改变。也因为客观原因,我们不善于维护多个对象以及多个对象之间的关系,所以我们对这个方法进行了改动或者简化。MVP定义了Presenter和View之间的接口,使得部分可以根据已有的接口协议独立开发,从而解决接口需求频繁变化的问题。上面两个图都有接口,只是接口的实现和使用细节不同,但是思路是一样的。这里要提一下,其实离用户最近的接口不一定是需求变化最频繁的接口,但是基本可以肯定的是,离用户最近的接口是需求变化最需要变化的。当然,如果View是API而不是UI,那就另当别论了。还有一些是用来“解决”MVC的这个缺点的,比如:ASP.NETMVC的ViewBag,Cocoa的delegate。它们都是为了简化更新数据的问题而存在的,包括MVVM。Model-View-ViewModel先直接看Model-View-ViewModel(MVVM)的图:从图上看,比MVP简单,更不用说MVC了。我个人不认为MVVM是从MVP演变而来的。我只是觉得这是MVP之后出现的一个“更好”的UI模式解决方案,但是和MVP对比更容易说明问题。ViewModel大致就是MVP的Presenter和MVC的Controller,View和ViewModel之间没有MVP接口,而是直接交互,采用数据“绑定”的形式,让数据更新事件不需要开发者手动编写Special用例,而是自动双向同步。您可以将数据绑定视为观察者模式或发布/订阅模式。其原理是采用统一集中的方式实现需要实现的数据频繁更新。与MVP相比,MVVM不仅简化了业务与接口之间的依赖,还针对频繁的数据更新优化了解决方案,甚至可以说是提供了一种行之有效的解决模式。到目前为止,我们可以理解为什么很多人认为MVVM是最好的模式,而不是其中之一。但实际上,MVVM也依赖于我们目前所说的“特殊情况”。当然,最优雅、最有代表性的做法是WindowsPresentationFoundation(WPF)。在#p#Web上,我们对模型演进的推论基本都是基于桌面软件,但过去十年是互联网时代。其实大家争论的最多的不是桌面领域的最合适,而是Web领域的模型问题,也就是B/S场景下的问题。当软件离开单机走向网络时,因为场景变了,原来的方案也变了,但是需求还是一样的。我们还需要解决的问题是用户交互和数据更新的问题,以及维护等问题。当场景换到Web上时,我们发现MVVM对于服务端是极其不适用的,至少目前是这样。而且您甚至不需要提及MVP。为什么?因为:网络资源成本太高。开发成本太高。让我问你一个问题。当一个网页的数据更新时,你想更新用户看到的数据。你会怎么做?一般情况下,你会:window.location.reload();即使你不这样做,用户也会:F5如前所述,我们会选择更直接的方式来解决问题。之所以直接刷新页面,是因为更直接,更容易解决数据更新的问题。很多时候你不会愿意为一个数据更新写一个AJAX,更何况这个AJAX还会带来Loading、事件序列处理、网络问题、异常处理等等,就是开发成本太高了。另一种解释是网络的高成本更容易解释。宽带虽然基本都是包月,但也不是这么用的,更何况还有移动用户。更重要的原因是,在本地软件中,更新数据是一个引用问题,而在网络应用中,则是一个传输问题。传输成本远高于引用成本,引用至多是本地内存中的另一个内存副本。这个时候,我们会更倾向于使用MVC模型,因为在Web层面,我们更倾向于一次性更新数据。Web上所有MVVM的问题都不是问题,即使有问题也要解决。为什么这个标题下会冒出这么一句话?我想说的是,需求依旧,是进步的原动力。另外,我之前也说过,当我们讨论或争论一个问题时,问题的对象发生了变化,这次在我们讨论问题之前就发生了变化。网络资源成本持续下降,相信不用多说。摩尔定律和一些类似的原理正在发挥它的应用作用,网络带宽越来越高,相应的速度也越来越快。如果数据传输的成本低于开发者因为相对成本下降而拒绝客户端的成本,那么它会被执行而不是被拒绝。还有一点,由于技术的进步,技术资源不断被更大规模地挤压,需求不断增加,所以需求总是会增加到超出相对恒定的开发成本。比如jQuery的出现,解决了很多问题。我们现在使用AJAX比较多,即使很大一部分还是为了解决网络资源不足的问题;我们将使用更多的样式代码和相对较少的图片;我们不是那么依赖像Flash这样的矢量图形解决方案,而是直接录制视频。至少我们上一节提到的导致大家选择MVC的两个问题正在得到解决,所以我们有理由相信未来的Web不仅需要MVC,还可能需要MVVM或者其他的解决方案。至少我们可以理解为什么前端会出现一些MVVM框架,比如先驱者knockout.js和AngularJs。这些框架本身的优点就不讨论了,因为我们讨论的是模式。在Web上,MVVM的对比对象不是MVC,而是CodeBlock。实时数据更新的需求在不断扩大,但可能没有一个高层模型必须使用MVVM。其实如果要更新一条数据,还是会用:$('.notice').html('发送成功!');因为……我们还是会采取更直接的方式来解决问题……其实现在WebMVVM主要不是用在Web或者Wap上,而是移动端App更胜一筹。按照前面的说法,只能是:HTML+JS在某些场景下比原生更适合Native,MVVM比Web更适合移动App,甚至是原生开发。其实iOS开发也使用类似的数据绑定。的方法。这里就不深究了,毕竟我也不是很懂iOS。我想说的是,在WebMVVM或者Web模型上,也就是在Web的富应用上,还只是一个由扩大需求驱动的初级阶段。重要的不是技术怎么走,而是需求和客观条件怎么走。也许Webform会因为高速发展而迎来第二春,其AJAX模式也很满足于简单的开发,但似乎大家需要的并不是GUI风格的网页。结论我们不一定需要MVVM,但我们肯定需要一种更强大的方法来解决不断扩展的Web需求。我们可以预见的是:将会有更强大的浏览器,更强大的JavaScript或框架,以及更适合的模型。客套话之外,我还是想说,针对不同的需求,其实都有最适合的解决方案,通常让我们纠结的不是因为哪个解决方案更好,而是因为我们没有看到足够的条件。编译型语言当然比解释型语言效率更高,但是考虑到开发和维护成本,JavaScript永远会流行,比如Node.JS,Python;.NET和微软当然很强大,把.NET移植到其他平台也很容易,但它是一家有自己商业模式和赚钱的公司;当然有些做法和技术更好,但其他开发者会回避甚至否认他们不擅长的东西,每个人都喜欢某些东西;有些技术再厉害,也只是基于特殊的客观条件和需求,要想做大,要么创造客观条件,要么结合需求……原文链接:http://www.cnblogs。com/indream/p/?2348.html