何时应该创建一个领域对象和持久化对象而不是使用持久化对象作为领域对象?

10
随着我对领域驱动设计的理解,我发现了一个规则似乎行之有效,但我想知道它是否过于严格,并希望看到其他人对同一情况的不同观点。
我的问题是:“何时应将域模型和持久化模型包含在单独的对象中?”我目前使用的语言是Java,使用Spring Data的存储库模型。
我认为有三种主要答案:
1.始终使用单独的域对象和持久化对象。 2.仅在将域方法(行为)放在持久化对象上不实际时使用单独的域对象。 3.在所有情况下将持久化对象用作域对象。
为了提问关于DDD的问题,我发现必须使用一个示例有界上下文,因为我还不了解足够抽象的DDD问题。
这是我的说明性有界上下文:假设我有一个法律编码系统,具有以下业务规则:
1.每本法律都必须分类。 2.每个法律都有一个标识符,由编码号前缀和编码共同分配后缀组成。 (例如:100-0100、599-2030)。 3.有多个使用法律编码系统的法律管辖区,他们应该能够进行自己的共同分配,但编码前缀是全局的,必须在所有管辖区内相同,以便促进一般可比性。 4.编码号前缀分组为广泛的编码类别。编码类别具有数字范围,例如100-199、200-299、700-799等。
要将此有界上下文表示为持久化模型,我有以下内容:
table: codification
fields: chart_code, prefix, coassign, codification_category

table: codification_chart
fields: chart_code, jurisdiction_description

table: codification_category
fields: category, low_category_number, high_category_number, description

table: global_codification
fields: prefix, coassign, codification_category

我知道,我应该先从领域模型开始。我有一个持久性模型和一个领域模型。
在我的领域模型中,我有三个领域对象。
public Codification {
    private String prefix, coassign;
    codificationCategory codificationCaegory; // an enum type
    public Codification(...) { // set private vars }
    // getters for private variables
}

public CodificationChart {
    private List<Codification> chartCodifications = new ArrayList<>();
    private String chartCode;
    // public constructor to initialize private variables
    // getters for private variables
    public Codification addCodificationToChart(Codification){...}
    public void removeCodificationFromChart(Codification){...}
    public boolean checkCodificationInChart(Codification){...}
}

public enum CodificationCategory {
    CIVIL, CRIMINAL, PROPERTY, CORPORATE, FAMILY, CONSUMER, ETHICS, BANKRUPTCY;
}

ORM对象:

JPA Mappings of the tables mentioned earlier with the "Entity" suffix added to their table names. 
They are omitted for brevity. 
Each one contains getters and setters like JPA Pojos do. 
If someone asks for the Persistence objects code I will post it.

我的领域对象只在我的工厂对象CodificationChartFactory中了解持久性模型,该工厂具有我用于与先前提到的ORM对象交互的存储库接口。这个工厂是领域中唯一使用持久性存储库的部分,因此是唯一与持久性层交互的部分。

在此创建单独的领域模型是否是浪费努力? 我可以看出我如何将我的CodificationChart行为放在一个持久性对象上。但是,将这些行为放在仅从数据库检索记录的持久性对象上感觉不太对。

我肯定会受到纠正。

1个回答

8
两种方法都是正确的,这取决于设计上个人的喜好。有些人不希望他们的领域对象与持久性有任何关系,因此会创建一个额外的Entity对象层...有些人则认为这并不是一个主要问题,因此愿意继续使用领域对象作为持久化对象。
就我个人而言(很主观),我认为使用JPA并拥有额外的实体对象层是错误的方法。ORM(如Hibernate)的目标是成为对象和关系模型之间的桥梁(我知道这个名称中包含了“R”)。我认为,如果想要保持分离,更好的方法是使用类似mybatis或纯SQL的东西,但绝对不是JPA...否则只是为了增加复杂性而增加复杂性(JPA不是最容易学习的框架之一)。
我乐意接受混合并注释我的领域对象。因为我知道它可以使持久化更易于管理...但与此同时,我也非常熟悉Hibernate/JPA,并且已经使用了10年:)。
3年前,我曾提出一个非常类似的问题,发布在程序员社区网站上-ORM是否支持创建丰富的领域模型?

谢谢你的观点。我有点害怕混合领域和持久化,因为我认为其他专业人士不这样做。我会尝试一下,看看自己是否喜欢。我同意,在使用JPA的情况下保持分离似乎是另一层不必要的复杂性。我喜欢你更倾向于将事物放在一起的回答。我想看到有人提倡将它们分开的答案,以便我可以看看在使用JPA的情况下是否有任何好理由这样做。 - Kent Bull
这也正是我所处的位置,感谢Augusto比我表达得更好 :) 此外,我不太了解Java,但是是否有一种替代“侵入式”JPA注释的方法,其中映射细节将被外部化为某种“流畅映射”文件(就像旧日子里的XML ORM配置一样,但在代码中)? 在我看来,这将对持久性无知非常有帮助。 - guillaume31
Hibernate仍然支持XML映射(许多年前我有同事喜欢这种方法,因此生产代码和映射之间没有静态关联)。我不知道是否有任何扩展可以允许在漂亮的DSL中定义映射...但可能是建立一个的问题(不幸的是,它将是ORM特定的)。最后...我从未见过Java中数据访问是100%透明的应用程序,它总是一个泄漏的抽象。 - Augusto

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接