如何理解Web应用程序的MVC模型?

本文首发于知乎,曾被好东西传送门/湾区日报BayArea/前端开发博客收录为头条推送

Web 开发不一定要遵循 MVC 模型,甚至现代 Web 应用开发越来越不适合 MVC 模型。而且,不同应用情况下,MVC 的形态会天差地别。脱离应用环境谈 MVC 是没有意义的。

回到正题,我觉得题主之所以觉得 C 不好理解,很大程度是“控制器”这个词本身表意不明所致。我当初就想:

  1. 一个应用的控制者当然应该是用户啊,程序里面冒出个 Controller 是闹哪样?(有兴趣可以看那篇著名的“名词王国的死刑”Stevey's Blog Rants: Execution in the Kingdom of Nouns)

  2. 如果参照电视遥控器来理解,C 光负责用户的输入(对应各种“Action”),那为嘛不叫 router?程序里搞一堆 Controller 文件只是完成 router 的作用不是很傻么?

  3. 如果不理解为遥控器,主语“控制者”算是个幽灵,那“控制”的宾语是 Model 是吧,那 Model 还控制 View 呢,凭什么 Model 就不是“Controller”?
    好在那时候单页应用还不太流行,否则没有了那么多对应 URL 的 action,用户输入都成了 JS 事件,Controller 就更加流离失所了。

~~~~~~~~~~~~~~~~~~~~~
但作为一个大学时代写过各种留言板、教务系统和资产管理系统的码狗,我很快发现了 C 的存在价值:用于弥合“需求”和“模型”的缝隙。

在架构一个应用时,我们要建立模型,说得土一点就是建表,然后设定对这些表的各种可能操作。比如建一个 students 表,允许关联班级、导师,然后定义增删改查的操作,别搞出漏洞或者脏数据……这些事情完成,我们就实现了“领域模型”或者说“业务逻辑”(domain logic/business logic)。

但我们没有办法根据“需求”直接架构这些 Model。需求是多变的,甚至是感性的、碎片化的。而“Model”需要实打实地对应一个面向对象编程意义上的“对象”,追求单一性、里氏可替换、接口分离、开闭原则……一堆原则。

在现实中,我们不可能对“需求”使用“单一性”原则。用户打开一个知乎用户页就想看到他赞过的帖子他发表的回答;打开一篇网易新闻就想看脑残评论;打开一本文艺作品就想聆听习总在文艺座谈会上的讲话……如果把各种需求都塞到模型里,会产生大量冗余和重复的代码。

此外,对象之间天然不擅长走“工作流”,所以涉及“提交了 A 然后进入 B 页面”这种应用层面的流程需求,也很难用 Model 对象表达。

何况,需求之间也是存在“继承”的,比如一个网站的一大波页面都需要展示用户的登录信息和头像。这种数据如果你不想在 V 里面直接读 Model 的话,就只有靠 C 之间的继承来传递了。

如果一个应用同时有网站、移动 APP 和 API 接口就更容易理解了,Model 在不同应用之间应当是可以复用的,因为它走的是“业务逻辑”。

所以,我们不妨把 C 理解为“用户需求的一种抽象”。除了负责倾听用户,还负责给用户所有他需要的数据(这有些接近 ViewModel 的概念了)。这部分东西,其实也被称为“应用逻辑”(application logic)。

如果应用是个 RESTFul 的 API,那可能几乎没有 C,因为它的“用户”非常“理性”(同理,题主的例子需求是既简单又单一的“查库”,够理性,C 也没啥用)。但对于 RSS,C 可能又是必要的,但依然几乎没有 V。对于报表应用, CMS,SNS,管理后台……不同形态的应用,MVC 的情况会是天差地别。

另外:
虽然题主觉得“对 V 比较理解”。但 View 可能恰恰是 Web 程序最难说清楚的地方。

按上面对 MVC 的定义,M 和 C 的分野在业务逻辑(domain logic/business logic)和应用逻辑(application logic),而 View 仅仅是视图。

但在 Web 领域里已经没那么简单,由于前端越来越多地承担了应用逻辑的功能(毕竟用户输入都是绑定在 DOM 上的),所以承担“用户和系统之间连接”的更多是 View。这时 View 其实是“控件”而非“视图”了。


嗨,谢谢你读到这里。网站没有留言/互动功能。如需交流想法,可以搜索微信视频号「多余取景器」点击复制 找到我,也可以加我微信:nuxuil 点击复制

HOME