这个贴子是从“代码擂台”转过来的。我想专门讨论一下这个问题。
MVC的概念已经深入人心,是经常被大家经常提到的法宝利器。
我感到有必要澄清MVC的概念和来龙去脉,以便大家有一个共识,有一个共同讨论的基础,以便能够把讨论更深入地进行下去,解决真正的问题,而不是在一些技术概念上绕圈子。
一般来说,我不喜欢在名词概念上做文章,发表看法和评论。因为有更多的真正有挑战性的问题需要解决。但通过这段时间的讨论,我感到一种这样的危险:
我们程序员是否过于迷信MVC之类的名词概念,是否可能因此而减弱了或丧失了独立思考的能力?
所以我甘冒天下之大不韪,直言不讳了。
先举一个例子。
很多程序员言必讲,“和页面显示相关的逻辑,只应该存在于View里面,而不应该存在于任何其它部分的代码里面。”
但很少有人真正思考,这个概念从何而来。大家隐约地觉得这个概念来自于MVC。但为什么会有这个概念?这个概念的真实来源是什么?
其实,MVC中关于View的原意是这么说的,“View里面只应该存在和显示有关的逻辑,而不应该存在任何其它的逻辑——比如访问数据库,调用业务逻辑之类”。
纠其源头,这是针对很多程序员在JSP中调用JDBC的现象。
大家仔细比较一下这两句话的区别。可以看出对一个概念的执著和崇拜能够达到怎样的一种潜移默化的思维效果。
本意是为了降低View的作用,只让View做这一件事情,不让View做越权的事情。结果成为:只有View才能做这件事情,其它部分没有权利做这件事情。
那么我们来看,所有的MVC框架中,View部分做到了“只和显示逻辑相关” 吗?View能够脱离数据部分单独存在吗?不管是用JSP,Velocity,还是用TagLib,View都必须知道自己所使用的Object的数据结构,必须访问这些Object的各种属性,才能把它们显示出来。这个View和Model分开了吗?能分开吗?
从概念来讲,MVC是一个完备的概念吗?能够自圆其说吗?
Struts是最流行的Web框架,也正是Struts令MVC概念风靡世界,成为Web程序员的圣经。
下面,我们来确认一下什么是MVC和MVC的来龙去脉。
MVC要求,Model把数据填充到request.attribute里面,通过Controller转发,View再把这些数据从request.attribute里面拽出来显示。
为什么需要这个过程呢?不知道大家想过这个问题吗?更深一步,有没有想过为什么Servlet规范需要request.attribute这个定义呢?
因为你没有别的方式把数据从Model传到View里面去。
MVC是为了解决JSP的天生缺陷而引入(原文为创造,错误)的。因为JSP是Servlet。你必须请求Web Server帮你定位并调用JSP/Servlet。
你必须调用 request.getRequestDispatcher("your.jsp").include().
既然如此,如何在Servlet之间传输数据?只能通过request.attribute。
Velocity本来和MVC毫无关系,你完全可以在Action里面直接定位调用Velocity Template。
但为了支持MVC,Velocity不得已做了妥协,做了Velocity-tools,来支持MVC。
有兴趣请阅读org.apache.velocity.tools.view.servlet的
VelocityViewServlet类的代码。
你可以看到,Velocity是如何支持MVC的,付出了如何的代价。
Servlet规范又付出了怎样的代价。
参见VelocityViewServlet类的一段代码。
代码:
* @return Velocity Template object or null
*/
protected Template handleRequest(HttpServletRequest request,
HttpServletResponse response,
Context ctx)
throws Exception
{
// If we get here from RequestDispatcher.include(), getServletPath()
// will return the original (wrong) URI requested. The following special
// attribute holds the correct path. See section 8.3 of the Servlet
// 2.3 specification.
String path = (String)request.getAttribute("javax.servlet.include.servlet_path");
if (path == null)
{
path = request.getServletPath();
}
return getTemplate(path);
}
fastm不具有JSP + TagLib的缺陷,没有需要MVC结构的根本需求。
下面我们探究一下,fastm的Data和View分离做的更好?还是MVC的Data和View分离做的更好?
MVC的View需要了解处理各种类型的Data Object。MVC的View需要知道它们的属性名,甚至需要知道这些Data Object的属性代表什么意义,根据这些属性的值,决定怎样的显示方式(比如,赤字,还是蓝字)。这不是业务逻辑是什么?
fastm的View(我是指Template DOM)只需要处理一种类型的Data Object – ValueSet DOM。ValueSet DOM本身就是数据和模板之间的桥梁,ValueSet DOM同时存放了数据之间的层次关系和数据本身,这正是DOM结构的精华所在。
另外,还有一个情况就是,似乎很少有人认识到DOM概念的重要性,大部分人都执著于Page Scripting技术(JSP,Velocity)。
另一个很古怪的现象就是,TagLib和Page Compent的概念,天生就是和Page Scripting技术(JSP,Velocity)技术 是对立的思路,却共存在View中,也从来没有人质疑。大家都把这当作一种经典思路,努力消化接受了,还研究颇深。其实这不过是 技术自身“修修补补”的结果而已。