Hibernate实体与域模型相同吗?
请参见下面的示例。
**方法1-域模型和实体是同一个类。域名模型是一个实体
@Entity
@Table(name = "agent")
class Agent
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "agent_number", unique = true, nullable = false)
private String agentNumber;
@Column(name = "agent_name", nullable = false)
private String agentName;
// Busines logic methods
}
**方法2-域和实体是不同的功能。域名模型“有一个”实体
class Agent
{
// Hibernate entity for this domain model
private AgentEntity agentEntity;
// Getters and setters to set the agentEntity attributes
// Business logic
}
从以上两种方法中,哪一种是实现DDD的正确方式?我相信方法2是正确的,因为您实质上是在控制对敏感对象的访问,并且封闭对象(域模型)具有域模型上的所有业务逻辑/操作。
但我的职场同事表示,它们本质上是一样的。根据它们,Hibernate实体的目的是表示给定系统中的领域模型。将实体建模为域模型实际上使设计变得更简单。这是因为存储库需要一个实体来执行CRUD操作。
因此,如果模型“有一个”实体,则必须将存储库依赖注入到域模型中以保存该实体。这将使设计变得不必要地复杂。
2条答案
按热度按时间n3h0vuf21#
既然您在本例中提到了一种技术,那就意味着您正在谈论一种实现。域驱动设计既是抽象的,比如模型,也是它的实现。
模型可以有不同的实现方式。在您的示例中,您展示了代表相同模型的两种不同实现。
这篇article讲述了您面临的问题。
您问域模型是否等同于Hibernate实体。答案是否定的。
Hibernate Entity是特定于技术的东西,在这种情况下,它是ORM框架的一部分。DDD定义的Hibernate Entity和DDD Entity是不同的东西,因为DDD Entity是一个抽象的东西,如果定义了一个想法(模式),并给出了这个想法是什么以及它代表什么的指导方针。Hibernate Entity是一个被示例化、跟踪、持久化、丢弃和垃圾回收的Java对象。
人们只是对不同的事物使用相同的术语,这可能会导致混淆(这不能怪他们,命名事物是软件中的两个难题之一)。
您可以使用Hibernaty Entity或任何其他类型的技术特定的东西,如Entity Frame Entity(这是同一件事,是OO程序中的对象)*来实现域模型。相同的域名模型可以使用不同的技术以不同的语言实现。这些实现将根据技术提供的内容而有所不同。
例如,如果您正在使用MongoDB编写NodeJS后端,并且您想使用ORM来实现域模型,那么您将不得不使用Active Record pattern(可能是Mongoose),因为这是人们实现的唯一框架(至少我找不到任何其他不是活动记录的框架,如果您找到任何框架,请让我知道)。以这种方式实现DDD可能非常棘手(并且可能非常糟糕)。
在DDD book中,Eric Evans讲述了技术如何帮助您实现模型或如何与您对抗。当它与你对抗或没有提供好的机制时,你只知道如何解决这个问题。
有时ORM有需求,而您不想将这些内容公开给其他代码,因此您可以使用方法2中的 Package 器。它们中的一些包括像公共的Get Set方法、公共构造函数等。它们中的大多数使用反射并且可以有私有的东西,但是仍然有很多问题,比如有一个没有参数的私有构造函数来满足框架,你的代码弄乱了许多与你的模型无关的东西,但是因为你的框架需要它们而存在(讨厌!)。这也可能导致错误。使用默认构造函数比使用带参数或静态工厂方法的好构造函数更容易出错。这个 Package 器可以表示更纯粹的领域模型,而不需要框架所携带的必要的邪恶,这样您就可以使用它们了。
在一个项目中,这变得如此难看,以至于我们决定在存储库中使用原始SQL,这样我们就不必处理框架的所有东西。实现很好,很纯粹,而且我们做得更快。有些人认为框架可以加快速度,这在大多数情况下是正确的,但当框架与您对抗并且代码有错误时,调试并不有趣,因此编写一个原始的SQL可能是轻而易举的。在这种情况下,遵循DDD的指导方针,通过使用聚合,我们的模型很好地解耦了,并且我们没有复杂的查询,这可能会降低开发速度。
mmvthczy2#
Hibernate实体是否与域模型相同?
不完全是,不是。在实践中,它们之间的界限可能非常模糊。
域驱动设计的一个主张是,您可以将持久性问题从域模型中分离出来。域模型在内存中保存了一些业务的当前状态表示,以及控制该业务状态如何随时间变化的域规则。
存储库充当一种边界,介于认为域实体都存储在某个本地内存中的应用程序部分和知道数据非易失性存储的代码部分之间。
换句话说,存储库(在某种意义上)是两个功能;一个知道如何从“聚合”和存储中获取数据,另一个知道如何从存储中读取数据并从存储中构建聚合。
ORM是将数据从外部关系数据库获取到本地内存的一种方法。
因此,您的负载情况可能如下所示
商店可能看起来像
在实践中,这是一种痛苦。ORM表示通常必须担心代理键、跟踪哪些数据元素是脏的以便优化写入等问题。
因此,您将经常看到的是,域逻辑最终被写入ORM实体,并且您抛出一堆注解,以清楚地表明存在哪些位,因为它们是Hibernate所需要的。
如果您查看DDD Cargo shipping示例,您将看到他们采用了第二种方法,其中聚合在底部隐藏了一些Hibernate支持。
域和实体是不同的功能。域模型“Has-an”实体
你的同事们是对的:在最重要的方面,它们是等同的。域模型取决于您的Hibernate实体。
它们都不符合埃文斯在书中所描述的。
这两个看起来都像许多球队在实践中所做的那样。据我所知,将域逻辑直接放入Hibernate实体是一种常见的方法。
如果您真的将这两者分开,那么您的存储库应该如下所示
如果仔细观察,您会发现域模型独立于Hibernate模型,但存储库依赖于两者。如果您需要更改持久化策略,则域模型保持不变。
额外的分离程度值得这么麻烦吗?那得看情况。在用于描述领域模型的面向对象模式和“无状态”执行环境之间存在着强烈的认知差异。