上周,我写了一篇文章“面向 Web 的 MVC 初学者指南”。其中,我叙述了框架使用 MVC 模式和“MVC”概念的一些问题。但是我没有给出更好的方法。我没有给出任何替代方案。因此让我们继续,谈谈 MVC 的一些替代方案……

MVC 的问题

让我们复述一下我们探讨过的 MVC 存在的根本问题:

● MVC 是有状态的

只有 View 和 View-Modle 的绑定是有状态的才有意义(这样 Model 才能在有变化时更新 View)。

● MVC 没有唯一的解释

每一个框架都使用它们自己的有细微差别的版本。

● 日志如何归类

那些不确定是否以数据为中心的应用程序代码应该从属应用程序的哪一部分?

Siblings To MVC

MVC 的同类

MVC 有很多同类,它们略有分歧差异很小。让我们来简单谈谈其中的一些:

HMVC - 分层-模型-视图-控制器

这种模式非常类似于 MVC 模式,除了你可以把多个三元组嵌套在一起。这样你可以为页面应用一个 MVC 结构,为导航应用一个,再为页面上的内容应用一个。如此“顶层”会把请求分配到导航和内容的 MVC 三元组。

这使得构建复杂页面更容易,因为它允许你创建可复用的小部件。但是它带来了 MVC 所具备的所有问题,并且没有解决它们(它只是增加了顶层的复杂程度)。

因此 HMVC 没有真正解决我们的问题……

MVVM - 模型-视图-视图模型

MVC 和 MVVM 之间的差异更加微妙。该模式的基本前提是,在标准的 MVC 中,View 同时做两件工作是不好的:呈现和表现数据逻辑。这意味着真正的渲染和渲染数据的处理之间是有差别的。因此 MVVM 把 MVC 的 View 分成了两部分。呈现(渲染)在 View 中进行。但是数据部分放进了 ViewModel。

ViewModel 可以和程序的其余部分交互,而 View 被绑定到 ViewModel。这意味着呈现与 Model 中的应用程序代码之间进一步分离。

控制器虽然没有被提到,但它仍然存在某个地方。

同样,此模式解决了 MVC 某些类型的问题,但是没有解决我们的任何问题。

MVP - 模型 视图 主持人

MVP 在实现上与 MVC 略有不同。与用 Controller 拦截用户交互和用 View 渲染数据不同,MVP 结构本身就有点儿不一样。View 负责被动呈现。这意味着它没有绑定到 Model,它只会渲染被给予的数据。不过它也接收用户交互事件(类似 MVC 的控制器)。总的来说,唯一暴露给用户的只有 View。

Presenter 位于 View 之后,控制所有的功能。当 View 收到用户交互后,它会将其转发给 Presenter。Presenter 会更新模型、拉取数据并把数据推送到 View 中。

就像 HMVC,它解决了 MVC 的一些问题。但是也像 HMVC 一样,它没有解决任何问题。

MVA - 模型视图适配器

MVA 把 MVC 中的 Controller 替换成了“Adapter”。不要混淆,这不是 “四人帮”设计模式Gang-Of-Four)中的 适配器模式Adapter),而更倾向于中介者模式Mediator)。

这意味着 Model 和 View 彼此间从未真通信。相反,它们通过“Adapter”通信(实际上就是一个事件驱动型 Controller)。

这样做的好处是 View 不再需要了解 Model。因此你可以实现更好的分离和解耦。

这也意味着 View 和 Model 之间的连接能够是无状态的!哇!终于搞定了!

然而并非如此。尽管 View 和 Model 之间可以是无状态的,但是实例本身仍然需要是有状态的。无状态部分只是它们之间的连接。

因此我们仍然卡在 MVC 同一根本问题上……

PAC - 表示 抽象 控制

我不打算在这里说太多,因为 PAC 实际上就像应用到 MVA 的 HMVC。基本上它就是 HMVA。带有所有相同的问题。

RMR - 资源 方法 呈现

在 RMR 架构中,你可以基于资源上的 HTTP 方法构建你的应用程序,然后呈现给用户。因此 MVC 的那些 Model 成了资源(它们会 1:1 映射到 REST 资源)。Controller 成了“Method”对象,View 成了 Representation。

这更新了 HTTP 网络的 MVC 架构。它允许我们构建更符合有请求参与的应用程序。并且,因为我们把应用程序更多地构建成资源上的操作,因此我们可以明显地简化交互。

这仍然没有真正解决有状态的问题。由于方法是对资源的操作,因此必须为每一个请求重新创建资源。这意味着需要为每一个请求重建整个三元组系统。哇。

更何况它根本没有解决其它两个问题。

更不用说它将自己和 HTTP 耦合得如此紧密,以至于想要把它映射到 CLI 或 GUI 接口都会非常困难。

ADR - 操作 领域 响应器

ADR 和 RMR 非常相近,它实际上就是调整了几处细节的同一模式。Action==Method,Resource==Domain 以及 Representation==Responder。我所看到的唯一明显差别是 Responder(RMR 中的呈现)对 Domain(资源)的了解程度。

它仍然存在像“日志应该放到哪儿”和必须在每个请求上重建状态的问题。并且它像 RMR 一样耦合到了 HTTP,因此很难创建非 HTTP 接口。

共性是什么?

关于我之前所提到的所有模式,有几点需要注意。让我们一个个来看。

● 都是三元组

我上面谈到的每一种模式都是一个三元组。这意味着它们都有三个组成部分。

有趣的是大于 90% 的主流应用模式都有 3 个组成部分。确实会让你好奇为何会这样……

我想,是不是因为每一种模式都是同一个基本概念的不同解释。与 SOLID 实际上只是一种概念一样,它所表现的不同,取决于你如何看待它。或许 MVC 就是那些模式中的一种。每个人都用不同的方式看待它,有些人意识到它的不同,就把它命名成别的什么名字。但是它们都同一基本概念。

● 所有的三元组拥有同样的概念

每个模式都有相似的思路:

  • 部分去处理渲染
  • 部分去处理交互
  • 部分去表现数据/业务规则

模式间的差异是,相互之间是如何工作的,以及哪一部分与哪一部分通信。

同样,我要问,日志放在哪儿?信用卡充值应该放在哪儿?应用程序的额外部分应该放在哪儿?

另外,为什么这三个部分是特别的?渲染总是单一任务吗?或者当它有多重任务时才应该分开?

都假装成应用程序架构

这就是重点。所有这些问题的根本问题。应用程序不只是有交互和呈现,还有更多内容。实际上,很多人会说交互和呈现是应用程序最小的部分(至少对大型程序来说)。

那么为什么我们要集中在交互阶段呢?

为什么我们关注我们程序的最小和最简单的部分,把其它所有东西都堆放进 Model 的杂物桶或模式之外?

这就是所有这些“模式”、“架构”和“原理”成为冷笑话的最大原因。它们解决了简单的问题,却不讲道理地丢出了困难的问题。

那么我们如何解决难题?

解决问题的第一步是,承认问题的存在。

如果我们继续假装问题不存在,那我们就无法对某些事情进行讨论。

有些人已经看到了问题,然后他们发明了类似 AOP(Aspect-Oriented-Programming)的东西来作为解决方案。

但是我不认为这是解决问题的正确方式。如果在你的应用程序中不清楚某些东西该放到哪儿,那就表明你的应用程序架构存在缺陷。而并不是说你需要因添加一些魔法来让它正常运行。

因此,让我们承认这些都不是应用程序架构……然后让我们承认我们有一个需要解决的问题。

至于解决方案……

好吧,下次再谈。


翻译自原文:Alternatives To MVC


Category: Tags: