MVC和存储库模式:控制器,模型和存储库的角色?

Jes*_*nch 9 php model-view-controller design-patterns repository-pattern

所以我一直在研究存储库模式的作用,作为在MVC框架中将持久层与我的模型分离的一种方法.在此之前,我可能UserModel直接使用我的调用活动记录方法来存储/检索域对象.

这是我正在考虑的关于应该创建新的请求中的调用堆栈的草图User:

在此输入图像描述

这是我的问题:

  1. 这是存储库模式的正确实现吗?
  2. 我知道控制器应该从请求中获取用户的信息并将其传递给模型.这通常是怎么发生的?控制器应该创建一个User对象,然后将其传递给模型吗?我确定不想只是将一组值传递到模型中 - 我也不想将15个参数传递给创建用户的模型方法.
  3. 为了使这个模式真正起作用,我觉得我需要有一个域对象,它只是一个没有行为的简单数据结构,然后如果我使用ORM,我会有一个ORM对象,它将描述对象是如何持久化的.最初我拒绝这一点,因为它感觉像是重复的代码,但如果我真的将持久性与业务逻辑分开,那么这需要吗?例如,如果我使用内存存储怎么办?我不再使用ORM对象了.

我在这里想得对吗?这是可以接受的.请帮助我连接我的脑袋.

ter*_*ško 17

1.这是存储库模式的正确实现吗?

我不确定你在做什么研究,但你弄错了.

  • 用于将域对象数据映射器分离的存储库.

  • 没有"模特"这样的东西.MVC设计模式中的模型是主要层之一:表示层模型层.

  • 存储库模式与活动记录(反)模式不兼容,后者在单个实例中组合了域和存储逻辑,从而导致严重的SRP违规.

要使用真实世界的示例,在何时以及如何使用存储库,这是一个示例:

您正在创建一些文档管理工具,其中所述文档可以来自多个来源(例如:本地SQL数据库,SOAP服务和缓存).在这种情况下,您将创建一个存储库,用于处理存储的"路由".应用程序的一部分决定了用于存储/检索每个文档的数据映射器.

存储库的目标是将域逻辑与存储交互分开.对于上面描述的系统,存储库还可以添加新的数据源,而无需重写大量代码(如果有的话).您可以为文档添加另一种类型的映射器.

2.控制器是否应该创建一个User对象然后将其传递给模型?

首先,控制器本身不应该创建任何东西.相反,您的控制器应该使用工厂来获取您需要的对象的实例.可以通过构造函数或其他方法将此工厂提供给控制器.这称为:依赖注入(了解更多信息,观看本讲座).

此外,如上所述,模型是一个层,而不是任何特定的类或对象.控制器的职责是改变模型层的状态(通过将数据传递给它).您可以直接在控制器中与域对象和映射器(或存储库)进行交互,但这意味着泄漏控制器中的某些业务逻辑.建议改为使用服务,然后操作所述域对象和存储相关结构.

至于10+参数的问题,你需要创建新的用户帐户,让我们假设你有以下足迹的行动:

public function postUser( Request $request )
{
    ....
}
Run Code Online (Sandbox Code Playgroud)

如果使用特定Request实例调用操作,则有两个选项可以处理大量参数:

  1. 将实例包装在装饰器中,这将允许您调用单个方法,以便在特定数组中根据请求形成数据.然后将此数组传递给服务.

  2. 在控制器的动作内部形成数组并传递它,需要数据.

前一种解决方案更适用于大规模应用,在这种应用中,除了代码之外,还需要重复进行这种数据的形成.但在小型/中型项目中,第二种选择是常识性方法.

事实上,控制器的工作是获取用户的输入,并将其分配给模型层和当前视图.这种阵列的形成符合这一要求.

3.(..)主要对象只是一个没有行为的简单数据结构然后(..)

不.域对象不是"简单数据".它是大多数域业务逻辑驻留在应用程序中的位置.

忘了神奇的ORM.实现存储库的第一步是分离域和存储逻辑.域对象处理验证和业务规则,映射器处理持久性和数据完整性(这里的小例子).

您必须意识到的另一件事是Web应用程序的存储库并不真正与内存持久性(除了缓存)交互.相反,您的存储库将为不同的数据源处理mappers.


cas*_*nca 1

控制器是否应该创建一个 User 对象然后将其传递到模型中?

我不确定你所说的“将其传递模型中”是什么意思——User对象就是模型。“控制器”和“模型”代表设计中的不同层,它们不是特定的对象,并且不应该UserModel像您提到的那样存在单独的对象。

存储库接口本身通常被认为是模型的一部分,尽管域对象不应该保存自己——这应该在控制器中完成。

然后,控制器的工作是解释请求并创建一个User对象,然后使用存储库来保存用户:

$user = new User(...); // based on Request
$repository->save($user);
Run Code Online (Sandbox Code Playgroud)

在我看来,我需要一个域对象,它只是一个没有行为的简单数据结构

这不是真的,您可以而且应该将行为封装在域对象中。至于持久性是如何实际实现的,一个好的 ORM 应该处理大部分细节,并且您不必手动创建额外的类。