在哪里建立新的域名实体?控制器,存储库或映射器?

时间:2012-03-15 21:23:43

标签: php instantiation separation-of-concerns

假设对于每个域实体,我都有一个为数据映射器提供API的存储库。例如,如果我有UserEntity,那么我会有一个UserRepository与UserMapper对话,以便在数据库中保存用户数据。

现在,假设表单已在网页上提交,我的控制器知道需要根据提交的信息创建新的UserEntity。

是吗:

  1. 当场新建UserEntity(),并根据提交的表单数据运行所有必需的setter方法,然后将UserEntity传递给repo,后者将传递给mapper进行插入?

    控制器创建UserEntity => Repo => Mapper => DB

  2. 将表单数据转换为数组,并将其传递给UserRepository,然后UserRepository运行新的UserEntity()和setter,并将其传递给mapper进行插入?

    控制器传递用户数据=> Repo创建UserEntity => Mapper => DB

  3. 将数组传递给UserRepository,UserRepository将数组传递给映射器以获取新的UserEntity和插入?

    控制器传递用户数据=> Repo传递用户数据=> Mapper创建UserEntity => DB

  4. 管理对象创建的责任是什么?

2 个答案:

答案 0 :(得分:2)

我知道这个问题已经过时了,但我认为我会把我的想法放在这里,因为唯一的答案还没有被正式接受,这可能对未来的搜索者有所帮助。要直接回答你的问题,我不会说上述问题。我更喜欢有一个额外的服务,如果你愿意的话,还有一个“经理”,用于促进控制器和repo / mapper对象之间的交互。每个模型都有一个专门的管理器来处理它的创建,更新和删除。

<强>控制器

我认为控制器是应用程序的粘合剂。我们可以将所有我们想要的问题分成尽可能多的部分,但是在某个地方,有些东西必须要理解视图侧和模型侧,并且该对象是控制器。话虽这么说,我相信控制器应该是瘦的,所以控制器唯一真正的工作就是将请求映射到响应。任何类型的中间处理都应该在其他地方开始。

在CRUD应用程序中,实例化新对象并将它们持久保存在控制器中很容易,即使它不止一次,因为它只需几行就可以粘贴。如果对象创建不是微不足道怎么办?我正在维护一个具有许多复杂关系的应用程序,而用户提交的创建通常需要同时创建许多对象。在仅控制器和模型环境中维护是不可行的。

额外服务图层

为了解决这个问题,我创建了2个额外的服务层:FormHandler和Manager。每次提交表单时,表单内容都会发送到表单处理程序层。表单处理程序负责理解进入的表单数据并使其正常化。然后,表单处理程序可以将数据传递给适当的管理器对象以进行处理。 Manager对象处理数据并更新域层。他们负责创建模型,更改模型,并将它们持久化到后端。

通过这种方式,控制器具有Request,Response,Form(可能,如果您的框架支持服务器端表单创建)和FormHandler的知识。表单处理程序具有表单(或表单数据)和管理器的知识。 Manager具有Repository,Mapper和Model的知识。请注意,现在,Managers是与Models和Mapper交互的唯一点,他们不了解Form数据或Request或Response。另一方面,控制器和表单处理程序不需要知道域层数据或持久性。

<强>结论

有了这个设计:

Controller -> FormHandler -> ModelManager -> Mapper

我发现我的所有课程现在都可以进行单元测试(甚至在某种程度上是控制器),因为关注点分离得很好,单点交互是避免重复逻辑的好处。

备注

我脑子里的回购只是为了查询数据库 - 询问它是否有东西,而不是创造新东西。

我在这种情况下的经验来自于使用Symfony 2和Doctrine 2。

因人而异;例如您可能会发现表单层是不必要的,但我发现从表单/视图数据到域模型理解的数据转换非常方便。

答案 1 :(得分:1)

这是一个难以回答的问题。由于几个原因,我的两分钱在第一位。首先,假设您的实体中有域验证,可以很好地拒绝传递的数据。如果在2或3中发生这种情况,那么在拒绝之前你已经深入了解了一些物体。就2/3和1之间的差异而言,它可能不是很多内存或执行时间,但它是一个区别。我试着快速失败。

其次,我认为控制器知道传入的数据以及对象是完全可以接受的。我同意“胖模型,瘦的控制器”,但是说控制器无法知道实体是否让控制器瘦了我的喜好。