也论PageController/FrontController与MVC

业界对于MVC这个名词的误解与滥用, 尤其是对与PageController和MVC的混淆, 在ASP.NET下, 比较典型的是出自于以下两篇文章里面的遣词造句:

http://www.microsoft.com/china/MSDN/library/architecture/patterns/esp/DesPageController.mspx?mfr=true
http://www.microsoft.com/china/MSDN/library/architecture/patterns/esp/DesFrontController.mspx?mfr=true

要从这两篇文章上来看, 有时会产生错误的结论, 似乎PageController是MVC. 实际上MSDN上早期有一篇文章, 介绍如何移植其它系统的MVC到.NET, 那里头说的是比较靠谱的. 其实狡猾的微软作者在这两篇文章中也并没有确切的说PageController或FrontController是MVC. 比如看这几句话:

"Front Controller。Front Controller 为所有页面请求定义同一个控制器,因此能够作出跨页的导航决定。"

这句话对FrontController的说法与MVC所具有的特征牛头不对马嘴. FrontController仅是控制器实现的一种模式,存在着很多情况应用了FrontController而没有应用MVC, 所以除了都有控制器之外不具有MVC的其它特征. 而且在这篇文章中所指的FrontController, "用于协调向 Web 应用程序发出的所有请求。此解决方案描述了使用单一控制器", 也和MVC的结构中Controller的作用是不符的. 单独列出Front Controller和MVC进行名词解释, 已经把它们针对的问题进行了区分, 但在文章开头却存在着故意的误导:

"您已经决定使用Model-View-Controller(MVC) 模式将动态 Web 应用程序的用户界面逻辑与业务逻辑分隔开来。您已经考察了Page Controller 模式,但您的页面控制器类具有复杂的逻辑,并且是较深的继承层次结构的一部分,或者,您的应用程序是基于可配置的规则来动态确定页面导航的。"

说实话这简直是乱七八糟. Front Controller能够解决页面导航, 身份验证等一系列问题, 其特点在于将通用的工作集中化, 这与MVC有什么关系? Front Controller模式要求关注Model吗? 我将Model和View在一起实现, 肯定不是MVC了吧, 然后用Front Controller导航, 就不是Front Controller了? 还是我说我这种实现是一个变体? 就像下面这句话一样?

"Model-View-Controller。Page Controller 是 MVC 控制器部分的实现变体。"

这句话通过所谓的"变体"二字, 硬生生把PageController与MVC扯上关系. PageController从本质上讲, 绝非MVC, 因为视角和针对的问题完全不同. 如果单独的考察每一个PageController, 实际上可以说是分布式的FrontController. 尤其是微软的实现方式, aspx作为view是aspx.cs的子类, 而Page又是HttpHandler的实现, 而Model在这种模式下可以根本不予提及. 这就是说View和Controller实际上是一个对象, 而Model到底如何实现, Model/View/Controller如何交互, 与PageController这种结构的特征毫无干系. PageController这个模式, 并不关注MVC所关注的问题, 它既不是MVC, 也绝不是MVC的一个子模式.

当然, 如果你Model以及Model与PageController的互动实现的妥当, 就变成了类似Document-View的模式, 微软把这种模式也叫做MVC的"变体", 用以在模式爱好者中间吸引初学者推广那臭名昭著的MFC. 这些说法纯属混水摸鱼滥竽充数的伎俩, 大家必须小心谨慎的注意, 虽然MFC和ASPX在一些方面都很好用, 管它们的实现方式叫MVC也不损害自己的利益, 但是如果被这些说法混淆了对名词的定义, 在你看纯技术文章中出现这些名词时, 可能会造成障碍; 而在写文章时, 由于传播了这些模棱两可的概念, 就会给初学者带来潜在的危害.

由于MVC作为一个时髦名词(其实已经有20年以上的历史了)最近广泛的流行, 被大规模滥用, 而且似乎代表着良好的设计, 所以基本上什么东西都要和MVC挂上勾. 比如上面两篇文章基本就是文字游戏, 可以说是微软忽悠模式跟随者的文章. 现在的普遍情况是, 只要能找出一个明确的Controller, 很多人就管这种方式叫MVC, 或MVC的一种"变体", 而根本不管Model和View的实现及特定的实现方式是否是该结构的实现所不可或缺的; 而MVC强调的就是Model/View/Controller之间的关系, 所以我个人认为不能把"能转换成MVC的结构"与"MVC结构"随便等同: 一个名词的定义涵盖范围越广, 它到底指代什么就越不可靠.

实际上, Fowler在一篇文章中明确的说过, 现在Web上广泛使用的方式, 叫做InputController更合适. 这点我也有所认同, 比如在RoR和php上的一些MVC的实现方式, 其实如果按照经典MVC的结构严格考察, 你说它不是完全完整的MVC也可以成立; 但是那些方式也确实接近于MVC拥有几乎全部MVC的基本特征, 所以叫做MVC比起PageController和FrontController更顺理成章. 完整的MVC -> 不完整的MVC, 不完整到一定地步, 就不能再叫做MVC了.

其实不是MVC, 不代表这种结构就不好不合理, 每一个模式都有自己如鱼得水的范围, 而不同模式的适用范围往往又有所重叠; 正是这种非要和MVC攀亲戚的做法, 反而使得PageController等模式在不知不觉间就矮了一头. 在Fowler的POEAA中, FrontController/PageController和MVC是不同的三个模式, 上面两篇MSDN文章在最后也给出了对POEAA的参考, 不可能不知道这种有广泛基础的划分方式, 说实话这样的文章比起糊涂人写的文章应该遭到唾弃.

另外需要说明的是, FrontController与(PageController或MVC), 我个人认为并非是互斥的模式. 刨除PageController是FrontController的一种分散式的特殊形式所带来的相似性之外, 实际上FrontController可以与PageController并存, 也可以与MVC并存, 作为更外围的控制器存在, 处理一些共同的需求. 比如关于前两天对于WebForm与MS MVC的讨论, 就可以实现一个FrontController, 然后WebForm更合适的地方使用WebForm(PageController), 而MVC更合适的地方使用MVC, 由FrontController提供对外的统一与导航, 并处理验证等通用任务.

个人感觉现在很多人包括一些不错的开发者对MVC/MVP/MVPC等模式结构的误解, 是由于没有统一的描述方式所决定的, 包括Fowler对于脚本/表模块/领域模型的割裂也是如此, 最近在构思一些能够较好的说明这些结构模式的详细描述的文章, 看看能不能这些问题一次说清楚, 给出一个共同的语言. 同时这种说明方式, 也能够顺便给ActiveRecord/Mapper等一系列话题明确的区分方式, 以及结合最近流行的Web应用给出一个初步指导, 判断以下问题:

1. 何时使用MV(P/C/PC), 或其它更复杂/简单的模式.
2. 何时使用表模块, 表入口等方式, 何时使用领域模型.
3. 何时及如何同时使用表模块等数据驱动方式与领域模型等更加面向对象的方式, 为什么它们是统一的而非Martin说的非此即彼.
4. 围绕这些话题展开的其它话题.
5. 给出你的做法的不合理性, 告诉你何时应该改变, 如何改变.
6. 给出你的做法的合理性, 你再也不需要为"我的做法不够面向对象"/"我的做法不是MVC"等是否高级的问题而苦恼.

很多人认为我的文章太长, 我保证我这些内容, 要比Martin的企业架构应用模式短的多, 精炼的多, 且绝对说的比他清楚. 作为一个我所定义的"入门者", 不是说我比Martin这样的人在这些方面有更深刻的认识; 但是作为在海边捡贝壳的孩子, 我感觉确实捡到一个更漂亮的贝壳, 可以更清楚的在一些问题的局部, 把故事讲的更清楚. 当然, 你要是认为一个中国人/一个普通开发者/一个身边的网友, 不可能拣到这样的贝壳, 你还是看那些商业文章更保险, 那我也无话可说, 我只是希望能够分享一下, 不要脸点说也趁机炫耀一下~

同时我最近正在自己正在使用这种描述方式进行实践指导, 还需要一些时间验证和修正, 有兴趣的朋友请耐心等待 :) .为了验证这种描述方式的可行性, 同时让Martin这些大牛/大嘴也可以参阅并改进一下, 我个人打算拿写成比较严谨的风格并翻译成英文, 不过我英文写作能力很差, 不知道是不是有人愿意合作呢? 另外这些内容也可扩展成书, 不过我完全没有出书的经验也没有时间去当一个合格的技术宣传者, 这方面要是谁愿意代劳, 也可以合作.

posted on 2007-10-15 04:50  怪怪  阅读(3234)  评论(25编辑  收藏

导航