所以我一直在研究存储库模式的作用,作为在MVC框架中将持久层与我的模型分离的一种方法。在此之前,我可能直接使用UserModel
调用活动记录方法来存储/检索域对象。
这是我正在考虑的关于应该创建新User
的请求中的调用堆栈的草图:
以下是我的问题:
我在这里想得对吗?这是可以接受的。请帮我把脑袋连接起来。
答案 0 :(得分:16)
我不确定你在做什么研究,但你错了。
没有“模特”这样的东西。 MVC设计模式中的模型是主要层之一:表示层和模型层。
存储库模式与active record(反)模式不兼容,模式在单个实例中结合了域和存储逻辑,从而导致严重SRP违规。
使用真实世界的示例,以及何时使用存储库是一个例子:
您正在创建一些文档管理工具,其中所述文档可以来自多个来源(例如:本地SQL数据库,SOAP服务和缓存)。在这种情况下,您将创建一个存储库,用于处理存储的“路由”。应用程序的一部分决定了用于存储/检索每个文档的数据映射器。
存储库的目标是将域逻辑与存储交互分开。对于上面描述的系统,存储库还可以添加新的数据源,而无需重写大量代码(如果有的话)。您可以为文档添加另一种类型的映射器。
首先,控制器本身不应该创建任何东西。相反,您的控制器应该使用工厂来获取您需要的对象的实例。可以通过构造函数或其他方法将此工厂提供给控制器。这称为:依赖注入(了解更多信息,watch this lecture)。
此外,如上所述,模型是一个层,而不是任何特定的类或对象。控制器的职责是改变模型层的状态(通过将数据传递给它)。您可以直接在控制器中与域对象和映射器(或存储库)进行交互,但这意味着泄漏控制器中的某些业务逻辑。建议改为使用services,然后操作所述域对象和存储相关结构。
至于10+参数的问题,您需要创建新的用户帐户,我们假设您有以下足迹的行动:
public function postUser( Request $request )
{
....
}
如果使用特定的Request
实例调用该操作,您有两个选项来处理大量参数:
将实例包装在decorator中,这样可以调用单个方法在特定数组中根据请求形成数据。然后将此数组传递给服务。
在控制器的操作中形成数组并传递它,需要数据。
前一种解决方案更适合大规模应用,在这种应用中,除了代码之外,还需要重复进行这种数据的形成。但在小型/中型项目中,第二种选择是常识性方法。
事情是,控制器的工作是获取用户的输入,并将其分发到模型层和当前视图。这种阵列的形成符合这一要求。
没有。域对象不是“简单数据”。它是大多数域业务逻辑驻留在应用程序中的位置。
忘记神奇的ORM。实现存储库的第一步是分离域和存储逻辑。域对象处理验证和业务规则,映射器处理持久性和数据完整性(小例子here)。
您必须意识到的另一件事是Web应用程序的存储库并不真正与内存持久性(除了缓存)进行交互。相反,您的存储库将为不同的数据源处理mappers。
答案 1 :(得分:1)
控制器是否应该创建一个User对象,然后将其传递给模型?
我不确定你的意思是“将传递给模型” - User
对象是模型。 “控制器”和“模型”代表设计中的不同层,它们不是特定的对象,并且不应该像您提到的那样单独的UserModel
对象。
存储库接口本身通常被认为是模型的一部分,尽管域对象不应该自己保存 - 这应该在控制器中完成。
您的控制器的工作就是解释请求并创建一个User
对象,然后使用存储库来保存用户:
$user = new User(...); // based on Request
$repository->save($user);
对我来说,我需要一个域对象,它只是一个没有行为的简单数据结构
事实并非如此,您可以而且应该在您的域对象中封装行为。至于如何实际执行持久性,一个好的ORM应该处理大部分细节,你不必手动创建其他类。