论坛首页 Java企业应用论坛

Web 应用的 MVC 到底和经典 MVC 有什么不同

浏览 7354 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-03-28  
Web 应用的 MVC 和经典的 MVC 显著不同

MVC 早期出现在桌面应用中。由于桌面应用的各个部分都运行在同一个进程(即便是后来流行的 C/S 应用,很大程度上也可以假想为同一逻辑进程)中,所以应用程序各个部分之间的交互都视为“可信任的”。

经典的 MVC 是 C 返回一个合适的 V。V 里面调用 M 获得数据,如果有什么 UI 上的事件发生,也是 V 里面直接去操作 M 了。因此在经典 MVC 中,应用程序逻辑是主要放到 V 中的。C 只完成应用程序逻辑中的小部分(分发不同的 V)。由于大部分应用程序逻辑是在 V 里面实现,所以 V 还要维持一个内部状态。

就拿大家前面的例子:输入框如果输入错误的数据,应该变成红色。

这个需求是典型的应用程序逻辑(更可以具体为一个 UI 逻辑),所以最好的实现场所就是 V 里面。在经典 MVC 中,控件输入数据会引发一系列的事件,而 V 可以拦截控件的 onchange 事件,从而设置控件的颜色。后来更进一步,将控件封装为对象,从而让控件对象负责自己的逻辑,V 就不用操心这些细节了。


到了 Web 时代,MVC 就变了

最关键的一点就是应程序被分成了浏览器端和服务端两部分。
对 MVC 的影响就是 V 现在也被分成了两部分,一部分放在浏览器端,一部分放在服务端。

还是那个输入框的例子,Web 应用处理起来有多种方式:

1、输入改变后,什么都不管,直到提交表单后,服务端对数据进行验证。如果验证失败,再重新构造整个用户界面,并且将输入框的属性改成红色。这个过程中,V 完全是被动的,仅仅是负责渲染 HTML 而已。
2、输入改变后,通过 Ajax 请求提交这个控件的数据,让服务端对数据进行验证。服务端返回特定的数据(例如一个 JSON)指示验证是否通过,V 里面的 JS 代码则根据返回结果更新输入框的颜色。
3、输入改变后,提交整个表单。然后服务端根据客户端的事件调用服务端的事件处理方法。事件处理方法中对控件数据进行验证,再更新控件的属性。最后服务端重新构造整个页面。
4、输入改变后,客户端的 JS 直接验证并更新控件状态。但整个表单提交到服务器后,还是得一一验证。

第一种是最传统的,也是最常用的。第二种则是 Ajax 兴起后流行的,不过现在大家也在反思这种模式是不是造成太多对服务器的请求。第三种则是 ASP.NET 的 POSTBACK 机制,JSF 我不了解,看介绍也是类似的机制。第四种实际上只是第一种的变形。

第一种模式:浏览器端完全不负责任何逻辑,仅仅是提供一个输入数据的接口,然后可以把数据提交到服务端。应用程序逻辑完全在服务端里面实现。
这种模式里面,V 实际上只是一个模板。服务端的 C 负责响应请求,然后验证浏览器端提交的数据,再调用 M 进行处理。最后根据处理结果,载入模板,渲染出 HTML 返回给浏览器。

第一种模式容易理解,而且实现简单,对浏览器端没有特殊要求,所以一直以来都是最主要的处理模式。但缺点就是用户体验不好,对用户操作不会有及时的反馈,而且没有办法根据用户操作实时的更新 UI。


第二种模式:浏览器端稍微主动点,会把 UI 事件报告给服务端。服务端处理后再反馈特定信息给浏览器端,浏览器端从而可以更新 UI。
比起第一种模式,第二种模式中的 V 会包含一些 JavaScript 代码。这些 JS 代码负责响应 UI 事件,然后把事件及相关的数据传递到服务端,并等待服务端的响应。服务端还是由 C 来处理,只不过处理完成之后仅仅是把处理结果返回给浏览器端(XML、JSON、字符串或者 JS 代码)。浏览器端的 JS 收到服务端的响应后,根据处理结果对 UI 做相应的更新。

这种模式的相对第一种来说有了不小的进步。用户操作可以马上得到反馈,而且可以构造非常动态的 UI。缺点则是需要编写大量的 JS 代码,服务端也要增加对应的响应代码。而且不同浏览器对 JS 的支持程度也不同,实践起来即使有各种 JS 框架的帮助也是比较繁琐的。


第三种模式:这种模式一个页面就是一个表单,JS 会去响应表单中的 UI 事件,然后根据事件类型决定是立即提交整个表单,还是稍后提交。
当表单提交后,服务端就不再是一个常规意义上的 C 来处理了,而是一个页面控制器(可以看作更复杂的 C)。页面控制器会根据定义,构造出整个页面的对象体系(例如 Page 对象中有两个 Textbox 对象)。构造好对象体系后,页面控制器会解析提交的表单中包含的事件。然后调用各个控件的事件响应方法。此时,就和桌面应用非常接近了。我们可以给各个控件编写事件响应代码,并在事件响应代码中调用 M 处理数据。当所有的事件都处理完成后,页面控制器会载入模板,然后传入对象体系,并通过复杂的渲染机制,将 UI 内容渲染出来返回给浏览器。

这种模式的好处很明显,那就是应用程序逻辑都在 V 里面完成。而且控件封装为了对象,控件的逻辑可以自己负责。缺点就是每次提交都是提交整个表单,数据量较大时明显会增加通讯量和延迟。而且早期的 Web 应用事件驱动模型会导致每次提交都重新构造整个页面,用户体验和效率也不怎么样。好在后来都有所改进,使用 Ajax 来提交表单和更新用户界面。


在上述三种模式中,我们会发现一个共同点:绝不在浏览器端实现应用程序逻辑。

因为浏览器端是不可控的运行环境,如果应用程序逻辑在浏览器端实现,那么安全性就得不到保证了。比如批量删除操作这个应用程序逻辑如果在浏览器端实现,用户完全可以自己分析浏览器端的代码和逻辑,直接构造一个表单来提交,从而绕过各种验证。

但是不在浏览器端实现应用程序逻辑,不代表不可以在 V 里面实现应用程序逻辑。要记住在 Web 应用中,V 是可以分成多个部分的,并且分别运行在服务端和浏览器端的,而且在服务端实现 V 也有很多种模式。实际上第三种模式就是典型,V 运行在服务端,并且完成所有的应用程序逻辑。


在服务端 V 中实现应用程序逻辑

比如我们可以在模板中写入应用程序逻辑,然后模板引擎解析模板时,通过嵌入模板的 tag 来调用 M 获得要呈现的数据。这种方式已经非常非常多的实现了,实际应用时对于显示各种数据是很方便的。但是这种模式没办法主动响应用户操作。所以后来出现的事件驱动才是最完整(但不是最完善)的解决方案。

可惜由于 Web 应用的天然特性,事件驱动不管怎么改善,都绕不开将整个表单提交到服务器的过程。所以事件驱动在 Web 应用上一直都没有成为主流。
   发表时间:2008-03-28  
dualface 写道
Web 应用的 MVC 和经典的 MVC 显著不同

MVC 早期出现在桌面应用中。由于桌面应用的各个部分都运行在同一个进程(即便是后来流行的 C/S 应用,很大程度上也可以假想为同一逻辑进程)中,所以应用程序各个部分之间的交互都视为“可信任的”。

经典的 MVC 是 C 返回一个合适的 V。V 里面调用 M 获得数据,如果有什么 UI 上的事件发生,也是 V 里面直接去操作 M 了。因此在经典 MVC 中,应用程序逻辑是主要放到 V 中的。C 只完成应用程序逻辑中的小部分(分发不同的 V)。由于大部分应用程序逻辑是在 V 里面实现,所以 V 还要维持一个内部状态。

就拿大家前面的例子:输入框如果输入错误的数据,应该变成红色。

这个需求是典型的应用程序逻辑(更可以具体为一个 UI 逻辑),所以最好的实现场所就是 V 里面。在经典 MVC 中,控件输入数据会引发一系列的事件,而 V 可以拦截控件的 onchange 事件,从而设置控件的颜色。后来更进一步,将控件封装为对象,从而让控件对象负责自己的逻辑,V 就不用操心这些细节了。

我觉得你对cs的mvc见解很有问题。
你原文说ui事件发生是在view里进行处理的,你认为mfc/wxWidgets/vcl中CWindow/wxWindow/TForm的继承类仅仅是一个view?

从本质上来讲,对话框类/面板类/Frame类及其子类作为视图类,应该只处理视图方面的工作,但是现实中他们的职责太大了,很多很多程序员在直接对话框的事件方法里写业务处理的代码,sql调用也直接写在里面,这符合mvc吗?

用当下流行的设计模式来思考一下一个对话框类的使用。
1.这些业务处理代码可以封装起来,那么有了dao类。
2.CRUD按钮都需要验证数据完整性,如果每个dao方法都调用一下,好烦,那么给对话框类添加消息处理,判断是CRUD按钮被点击就先执行validate方法。
2.对话框启动时需要初始化界面数据,代码封装起来,在OnInitDialog方法里调用一下。

好了,现在对话框类的功能就出来了,是控制器和视图的混合体。

接着我们可以更进一步:
1.既然每个对话框类初始化时都要将po的数据填充到控件里,那么干脆封装出来。
2.既然每个命令按钮都需要validate,那么也封装出来。
3.既然做业务处理前都需要将所有界面控件的值传到对象中,那么也封装出来。

很有趣的是,我看到wxWidgets封装了这个东西,wxWindow类有一个方法SetValidator,看看wxValidator类的其中三个方法
wxValidator::TransferFromWindow
wxValidator::TransferToWindow
wxValidator::Validate

所以楼主你所描述的经典MVC只能说是国内开发人员的经典手法,算不上对mvc的理解和深入。

我认为,传统cs没有发展出足够好的mvc框架,1是语言限制,2是各种操作系统差异的限制。
bs开发用的都是跨平台脚本语言或者基于虚拟机的语言,自然有很大的发挥余地。

但是java和.net的出现,给cs编程的mvc框架带来了生机。
eclipse的mvc框架,除了在系统数据配置(plugin.xml)方面进化很大,其他方面暂时没发现。
.net我还没研究,但是他一套框架统一了win form和web form,肯定有其特色。
0 请登录后投票
   发表时间:2008-03-28  
我觉得不是我理解不对哈。是你没有正确理解。我估计你是对我说那个“应用程序逻辑”没理解到。

按照《企业应用架构模式》一书的说法,应用程序逻辑主要是数据的输入输出以及用户交互方面的逻辑。而涉及到业务的逻辑称为领域逻辑。

所以我前面说:

引用
因此在经典 MVC 中,应用程序逻辑是主要放到 V 中的。


是没有问题的。


事实上,即便无数人喊 MVC,但是能把领域逻辑真正给封装到 M 里面去的,是少之又少。绝大部分人都在 C 或者 V 里面就把领域逻辑也给实现了。正如你说的 MFC、wxWeight 等,提供那么多类,本意就是让开发人员可以更好的处理应用程序逻辑,而不是让你把业务逻辑也放到这里去实现。但大家都觉得这样做省事,就不管了。最典型的例子就是 VB。VB 提供了极好的 IDE 和事件驱动开发,结果大家都把领域逻辑在用户界面里面实现了。但事实上,VB 是可以单独写 Model class 来封装领域逻辑的,只是大家不用罢了。

在严格的 MVC 模式中,V + C 负责应用程序逻辑,M 负责领域逻辑,分工相当的明确。
0 请登录后投票
   发表时间:2008-03-28  
引用

.net我还没研究,但是他一套框架统一了win form和web form,肯定有其特色。


Eclipse 我不了解就不谈了。但 .net 的框架其实不是像你想的那样是一套,而是好几套。ASP.NET 的 Web Form 和桌面应用的 Win Form 是两个不同的子框架。两者只是都基于事件驱动这种原理。

实际上,Win Form 和 Web Form 都是好心办了坏事。虽然提供了一个极好的基础,但大家都忽略了 M 的存在,把用户界面变成了“智能UI”。
0 请登录后投票
   发表时间:2008-03-28  
dualface 写道
引用

.net我还没研究,但是他一套框架统一了win form和web form,肯定有其特色。


Eclipse 我不了解就不谈了。但 .net 的框架其实不是像你想的那样是一套,而是好几套。ASP.NET 的 Web Form 和桌面应用的 Win Form 是两个不同的子框架。两者只是都基于事件驱动这种原理。

实际上,Win Form 和 Web Form 都是好心办了坏事。虽然提供了一个极好的基础,但大家都忽略了 M 的存在,把用户界面变成了“智能UI”。

你的意思是这种智能化导致使用微软产品的开发人员继续在事件方法里写业务代码吧,也就是你所说的"经典MVC"那样。
0 请登录后投票
   发表时间:2008-03-28  
我没说这种智能化是经典 MVC 啊。。。。。。

恰恰相反,这种智能化的UI是典型的反模式。


MVC 经典模式里面,V 是有很多逻辑,但只是应用程序逻辑,不是领域(业务)逻辑。这是重点。
0 请登录后投票
   发表时间:2008-03-28  
我认为MVC只有一种定义,因此没有经典MVC和web应用的MVC差异一说,有不同框架特色的差异之说,如果你的帖子讨论的是不同框架的差异,这个并没什么问题,但是说到经典MVC和web应用的MVC,就有问题了,MVC什么时候还分两个了?
0 请登录后投票
   发表时间:2008-03-28  
MVC 是一系列模式的统称,不是只有一种。你可以去维基看看,我这里上不了。
0 请登录后投票
   发表时间:2008-11-24  
看老廖的帖子真是一种享受啊,思路清晰,文笔还不错:)
0 请登录后投票
   发表时间:2008-11-24   最后修改:2008-11-24
LZ属于主观唯心主义.

MVC中各层的功能完全是设计的时候人为定义的,就算是LZ所说的WEB下的MVC,我也可以人为的把各层的功能设计成LZ所说的经典MVC那样,那你说我的这个MVC到底是属于哪一种?
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics