Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oop DDD:在何处放置持久性逻辑,何时使用ORM映射_Oop_Design Patterns_Domain Driven Design_Dao - Fatal编程技术网

Oop DDD:在何处放置持久性逻辑,何时使用ORM映射

Oop DDD:在何处放置持久性逻辑,何时使用ORM映射,oop,design-patterns,domain-driven-design,dao,Oop,Design Patterns,Domain Driven Design,Dao,我们将对我们的(Java)web应用程序模式进行长期、深入的研究。在过去,我们的对象模型过于贫乏,控制器、服务和DAO之间的分离过于程序化,简单的值对象(基本上只是数据包)在它们之间移动。我们使用了声明式(XML)管理的ORM(Hibernate)进行持久化。所有实体管理均在DAOs中进行 在尝试转移到更丰富的领域模型时,我们发现自己正在为如何最好地设计持久层而挣扎。我花了很多时间阅读和思考领域驱动的设计模式。不过,我想得到一些建议 首先,我更自信的是: 我们将在前端使用“精简”控制器,只处理

我们将对我们的(Java)web应用程序模式进行长期、深入的研究。在过去,我们的对象模型过于贫乏,控制器、服务和DAO之间的分离过于程序化,简单的值对象(基本上只是数据包)在它们之间移动。我们使用了声明式(XML)管理的ORM(Hibernate)进行持久化。所有实体管理均在DAOs中进行

在尝试转移到更丰富的领域模型时,我们发现自己正在为如何最好地设计持久层而挣扎。我花了很多时间阅读和思考领域驱动的设计模式。不过,我想得到一些建议

首先,我更自信的是:

  • 我们将在前端使用“精简”控制器,只处理HTTP和HTML—处理表单、验证和UI逻辑

  • 我们将有一个无状态业务逻辑服务层,它实现通用算法或逻辑,不知道UI,但非常清楚(并委托给)域模型

  • 我们将有一个更丰富的域模型,其中包含该域模型中对象固有的状态、关系和逻辑

问题在于坚持。以前,我们的服务将(通过Spring)注入DAO,并将使用像find()和save()这样的DAO方法来执行持久性。然而,更丰富的域模型似乎意味着对象应该知道如何保存和删除自己,也许更高级别的服务应该知道如何定位(查询)域对象

这里出现了一些问题和不确定性:

  • 我们是否希望将DAO注入域对象,以便它们可以在save()方法中执行“this.someDao.save(this)”操作?这有点尴尬,因为域对象不是单例对象,所以我们需要DAO的工厂或后期构造设置。从数据库加载实体时,这会变得很混乱。我知道SpringAOP可以用于此,但我无法让它工作(使用Play!framework,另一系列实验),而且它看起来相当混乱和神奇

  • 我们是否将DAOS(存储库)与完全无状态的业务逻辑服务保持完全分离?这可能有点道理,但这意味着如果“保存”或“删除”是域对象的固有操作,则域对象无法表达这些操作

  • 我们是否完全不使用DAO,而是使用JPA让实体自行管理

下面是下一个微妙之处:使用JPA映射实体非常方便。这出戏!框架也为我们提供了一个很好的实体基类,其中包含save()和delete()等操作。然而,这意味着我们的域模型实体与数据库结构紧密相连,我们使用大量持久性逻辑传递对象,可能一直到视图层。如果没有其他内容,这将降低域模型在其他上下文中的可重用性

如果我们想避免这种情况,那么我们需要某种映射DAO——要么使用简单的JDBC(或者至少是Spring的JdbcTemplate),要么使用数据库实体和“业务”实体的并行层次结构,DAO永远将信息从一个层次结构复制到另一个层次结构

这里合适的设计选择是什么


Martin

我不是Java专家,但我在.NET代码中使用了NHibernate,因此我的经验应该可以直接翻译到Java世界

当使用ORM(如您提到的Hibernate)构建域驱动的设计应用程序时,一个好的(我不会说是最佳的)实践是在UI和域之间创建所谓的应用程序服务。它们类似于您提到的无状态业务对象,但应该几乎不包含任何逻辑。它们应该是这样的:

public void SayHello(int id, String helloString)
{
    SomeDomainObject target = domainObjectRepository.findById(id); //This uses Hibernate to load the object.

    target.sayHello(helloString); //There is a single domain object method invocation per application service method.

    domainObjectRepository.Save(target); //This one is optional. Hibernate should already know that this object needs saving because it tracks changes.
}
对DomainObject包含的对象的任何更改(也向集合添加对象)都将由Hibernate处理

您还需要某种AOP来拦截应用程序服务方法调用,并在方法执行之前创建Hibernate会话,并在方法完成后保存更改,无异常


有一个非常好的示例,说明如何在Java中进行DDD。它基于Eric Evans的样本问题。应用程序逻辑类示例代码是。

您的问题和疑问在这里敲响了一个有趣的警钟,我认为您对“富域模型”的解释有点过头了。丰富性并不意味着持久性逻辑必须由域对象处理,换句话说,不,它们不应该知道如何保存和删除它们自己(至少不是明确地,尽管Hibernate实际上透明地添加了一些持久性逻辑)。这通常被称为持续无知

我建议您保留现有的DAO注入系统(对于单元测试来说,这是一件好事),保持持久性层不变,同时尝试将一些业务逻辑移动到适合的实体中。一个很好的起点是识别聚合并建立聚合根。它们通常包含比其他实体更多的业务逻辑


然而,这并不是说域对象应该包含所有逻辑(特别是不包含应用程序中许多其他对象所需的逻辑,这些对象通常属于服务)。

根据域驱动设计,域对象应该是持久性无关的。好吧,公平点。但是看看我问题的最后一部分:类似Hibernate/JPA的东西使持久性的处理变得更加容易。然而,如果我们在域模型上这样做,那么它就内置了这种逻辑。如果我们不这样做,那么我们要么完全放弃ORM,要么在它们之间有一个“映射”对象和“域”对象以及数据映射器的并行层次结构