MVC的迷失?

来源:互联网 发布:知乎高考参考书 编辑:程序博客网 时间:2024/06/11 06:54
作者:老王 http://hi.baidu.com/thinkinginlamp/blog/item/3a571d95d9d6060d7af48060.html

补充(2008-04-20):
本文中,似 乎我对Web MVC的理解有问题,最近这个老生常谈的话题把我折磨的够呛。这里我再理理思路:传统的MVC概念是应用在桌面软件之上的,V可以查询M,C可以改变M。 一条判断MVC的很重要的原则是View是否能动态的感知Model的变化,这在桌面软件上是很简单的,只要使用观测者模式就很容易办到,但是到了Web 环境下,因为HTTP是无状态的,我们无法让View去观察Model,所以传统的MVC概念在Web环境下必须做出调整,这里最著名的改进方案就算是 Sun公司针对Java做的Model2方案了,在Model2中,V并不直接和Mode打交道。一切和Model的交互都由Controller处理,然后Controller会把需要的Model数据放到一个View能找到的地方,并选择一个View去渲染结果。

基于这些认知,所以本文的一些观点可能并不正确,但我并不打算删除这篇文章,就留下来让大家继续讨论吧。


================================

MVC似乎早已成为一个让人感觉审美疲劳的名词了。仅PHP社区里,各种各样宣称支持MVC的框架少说也有几十种,不幸的是这些框架大部分都没有正确的实现MVC模式。今天容我老王卖一次瓜,说说目前这些所谓的MVC框架里疑是存在的问题。

首先一个问题是VIew是否有查询Model的权力?

在目前大多数MVC框架实现中,不管是修改Model状态的操作,还是查询Model状态的操作,所有和Model相关的操作都是在Controller 中进行的。VIew里如果需要Model数据,一般也是先在Controller里完成对Model的操作,然后把需要的数据set到View里,从程序 员的角度看,Controller在MVC中是一个中间人的角色。但我觉得这是错误的。因为在这样的MVC实现里,作为中间人存在的Controller 过于万能,而VIew则显得有些残疾。在我看来,MVC中,针对M的操作,V和C是平等的。唯一的区别在于当请求达到Controller的时候,如果是 修改Model状态的操作,会在Controller中进行,然后根据结果再转发给合适的View,如果仅仅是查询Model状态的操作,则 Controller只是简单的把请求转发给合适的View,由View去查询Model的状态。之所以要进行这样的区分是因为不同的View对 Model查询的需求也是不尽相同的,比如说一个列表页在IE浏览器里每页要显示100条,而在Ipnone手机里每页只能显示10条,这样的情况下,如 果Model的查询是通过Controller进行的,那么我们的Controller是查100条还是10条呢?你可能想为每个需求都单独做一个 Controller的Action方法,但那会产生若干一次性的方法,无疑是丑陋的解决方案,亦或许是进行某些if/else的判断,同样是自取其辱。 所以我们说,应该在View里查询Model,而不是Controller。

再一个问题是Controller处于表现层还是应用层?

关于分层,一般都倾向于表现层,应用层,领域层,持久层的划分方式,从上至下单向依赖,在PoEAA这样圣经级别的著作中,Controller一般是作 为表现层模式来介绍的,但实际上很多时候Controller是一个应用层模式。先来看一个例子,用户注册的时候,如果表单提交成功,会向用户的电子邮件 里发一封欢迎信。在这个例子里,我们的Controller会先调用Model的相关方法完成用户的注册,然后可以使用PhpMailer之类的东西发送 相关的电子邮件。假设Controller处于表现层,那么如果我们加入一个新的表现层,则无疑要重新实现一套Controller,这里就必然会导致重 复实现发送电子邮件的逻辑。换句话说,我们的Controller里时常掺杂着一些应用逻辑。所以此时的Controller实际是处于应用层的,而且, Controller中Action的划定通常是根据用例来实施的,它本身勾画了用例的自然轮廓,进而从一个侧面说明了Controller和应用层的联 系。

还有一个问题是Controller是否有权利redirect?

很多MVC框架的Controller都有一个和redirect相关的方法,用以实现从一个Action跳转到另一个Action的功能。但我要说明的 是,这本质上是错误的,因为跳转是一个View关注的行为,而不是Controller。前面我们已经说过了,Controller属于应用层,而非表现 层,一旦你在Controller里实现redirect操作,就会把表现层固化到Html界面之上,设想如果你要给你的应用实现一套命令行界面怎么办? 在命令行里可是没有跳转一说的。或者你要用Delphi实现一个客户端软件,通过SOAP调用你的Controller程序,同样,Delphi客户端软 件也不知道如何解析跳转。所以说Controller里不要使用redirect。

===============================

通过讨论,可以看到,焦点主要是集中在V和C上面,这并不奇怪,因为MVC本身就未涉及M的实现,归根到底,目前的MVC框架犯的主要错误就是没有清晰的切分V和C的职责,所以说他们不是正确的“M_V_C”,更像是一个“M_VC”。
原创粉丝点击