注意: MVC 和受 MVC 启发的模式是高级构造。它们旨在用于普通面向对象(遵循SOLID和其他准则)代码开始变得难以管理的代码库中。通过引入这种模式,您将施加额外的约束,从而使您能够包含非常复杂的应用程序。MVC不适用于“hello world”应用程序。
让我们从头开始 ...
MVC 和受 MVC 启发的设计模式背后的核心思想是关注点分离。所述分离是双重的:
模型层(不是“类”或“对象”)将包含几组结构,每组都作为业务逻辑的不同方面处理。主要部分是:
- 领域对象:验证、业务规则
- 存储抽象:来自域对象的数据的持久性和缓存
- 服务:应用逻辑
也可能混合在存储库、工作单元和其他中。
UI 层主要由视图和控制器组成。但它们都利用服务与模型层进行交互。服务为控制器提供了改变模型层状态的方法,并为视图提供了基于新状态收集信息的方法。
在 Web 上下文中,由于 Web 应用程序表现出的请求-响应特性,视图和控制器形成了松散的一对。
需要注意的是,虽然控制器可以直接改变当前视图的状态,但更常见的是这些改变是通过模型来实现的。直接更改视图的一个原因是,例如,当您需要使用 JSON 来响应而不是 XML 时。
尽管也可以争辩说,可以简单地为每种输出格式实例化不同的视图并利用多态性。
什么不是视图?
人们普遍认为视图只是美化的模板文件。这个错误在 RubyOnRails 原型框架发布后变得非常流行。
视图不是模板。如果你这样使用它们,你就打破了 MVC 和 MVC 启发模式背后的核心原则。
如果你假装模板是视图,它会对你的架构产生巨大的影响。视图中没有表示逻辑的位置,因此您可以在控制器或模型层中推送表示逻辑。通常的选择是“控制器”,因为大多数人都明白表示逻辑在模型层没有位置。
本质上,这会导致视图和控制器的合并。
视图在做什么?
视图的职责是处理表示逻辑。在网络环境中,视图的目标是对用户产生响应(顺便说一句,这是浏览器而不是人类)。
从技术上讲,可以创建客户端视图,即用户 Web 套接字来观察模型层,但实际上几乎不可能实现。尤其是在 PHP 环境中。
要创建此响应视图,需要从模型层获取信息,并根据收集到的数据,通过将数据分发到模板并呈现或有时简单地发送 HTTP 位置标头来组装响应。
当使用Post/Redirect/Get时,重定向部分由视图执行,而不是人们经常做的控制器。
高度主观的位:
最近我更喜欢使用以下方法与 MVC 交互:
// the factory for services was injected in constructors
$controller->{ $method.$command }($request);
$response = $view->{ $command }();
$response->send();
这$method
是当前的REQUEST_METHOD,它已经被调整为一个类似 REST 的 API,这$command
就是人们通常所说的“动作”。GET
控制器对请求和POST
(另一个)请求具有单独的例程。这有助于避免if
在每个“动作”中都出现相同的情况。
在视图中,我调用了类似命名的方法,它准备发送给客户端的响应。
警告:我怀疑此设置包含SRP违规。把它当作你自己的可能是个坏主意。
干呢?
您可能已经注意到,将视图作为实例存在一个小问题。你最终会得到重复的代码。例如:菜单或分页。
让我们看看分页.. 分页包含逻辑,但这个逻辑与模型层无关。该模型没有“页面”的概念。相反,这部分逻辑将驻留在 UI 层中。但是,如果您的每个视图都包含或继承了分页,那么这将明显违反 SRP(实际上也违反了其他几项原则)。
为了避免这个问题,您可以(并且应该,恕我直言)在您的视图中引入演示对象。
注意:虽然 Fowler 称它们为“演示模型”,但我认为这个名称只会增加整个“什么是模型”的混乱。因此,我建议将它们称为“演示对象”。
表示对象处理重复的逻辑片段。这使得视图“更轻”,并且在某些方面开始反映模型层的服务结构。
表示对象和模板之间的交互变得类似于域对象和数据映射器之间的交互。
我总是需要这一切吗?
不,这种特定方法主要针对代码,其中 UI 层具有很多复杂性,您需要将输入处理与表示分开,以保持理智。
如果您的应用程序具有非常简单的 UI,例如 .. emm .. 您正在为更大的集成项目制作 REST API。在这样的实用选项中,可以将每个控制器视图对合并到单个类中。
在重构遗留代码库时,这也是一个很好的步骤,因为这种约束较少的方法可以让您移动整个旧代码块。当您隔离了这些旧代码并检查了一切是否仍然有效(因为遗留代码从来没有任何测试......这就是它成为“遗留”的方式),然后您可以开始进一步拆分它,同时专注于分离业务逻辑从用户界面。
PS我自己仍在努力寻找一种如何最好地处理观点的方法。这篇文章不是一个答案,更像是我目前理解的快照。