模式:REPOSITORY

REPOSITORY模式是领域驱动设计中的一个重要概念,它作为模型与数据访问之间的抽象层,专注于领域对象的管理和查询。本文详细介绍了REPOSITORY模式的查询、实现、在框架中的应用以及与FACTORY模式的关系,强调了保持领域模型为中心的重要性,同时探讨了如何为关系数据库设计对象,以实现模型与数据库的合理映射。
摘要由CSDN通过智能技术生成

目录

 

模式:REPOSITORY

REPOSITORY的查询

客户代码可以忽略REPOSITORY的实现,但开发人员不能忽略

REPOSITORY的实现

在框架内工作

REPOSITORY与FACTORY的关系

为关系数据库设计对象


模式:REPOSITORY

我们可以通过对象之间的关联来找到对象。但当它处于生命周期的中间时,必须要有一个起点,以便从这个起点遍历到一个ENTITY或VALUE。

无论要用对象执行什么操作,都需要保持一个对它的引用。那么如何获得这个引用呢?一种方法是创建对象,因为创建操作将返回对新对象的引用。第二种方法是遍历关联。我们以一个已知对象作为起点,并向它请求一个关联的对象。这样的操作在任何面向对象的程序中都会大量用到,而且对象之间的这些链接使对象模型具有更强的表达能力。但我们必须首先获得作为起点的那个对象。

想到这种方法的人并不多(实现ENTITY和应用AGGREGATE),尝试它的人就更少了,因为人们将大部分对象存储在关系数据库中。这种存储技术使人们自然而然地使用第三种获取引用的方式——基于对象的属性,执行查询来找到对象;或者是找到对象的组成部分,然后重建它。

数据库搜索是全局可访问的,它使我们可以直接访问任何对象。由此,所有对象不需要相互联接起来,整个对象关系网就能够保持在可控的范围内。是提供遍历还是依靠搜索,这成为一个设计决策,需要在搜索的解耦与关联的内聚之间做出权衡。Customer对象应该保持该客户所有已订的Order吗?应该通过Customer ID字段在数据库中查找Order吗?恰当地结合搜索与关联将会得到易于理解的设计。

遗憾的是,开发人员一般不会过多地考虑这种精细的设计,因为他们满脑子都是需要用到的机制,以便很有技巧地利用它们来实现对象的存储、取回和最终删除。

现在,从技术的观点来看,检索已存储对象实际上属于创建对象的范畴,因为从数据库中检索出来的数据要被用来组装新的对象。实际上,由于需要经常编写这样的代码,我们对此形成了根深蒂固的观念。但从概念上讲,对象检索发生在ENTITY生命周期的中间。不能只是因为我们将Customer对象保存在数据库中,而后把它检索出来,这个Customer就代表了一个新客户。为了记住这个区别,我把使用已存储的数据创建实例的过程称为重建。

领域驱动设计的目标是通过关注领域模型(而不是技术)来创建更好的软件。假设开发人员构造了一个SQL查询,并将它传递给基础设施层中的某个查询服务,然后再根据得到的表行数据的结果集提取出所需信息,最后将这些信息传递给构造函数或FACTORY。开发人员执行这一连串操作的时候,早已不再把模型当作重点了。我们很自然地会把对象看作容器来放臵查询出来的数据,这样整个设计就转向了数据处理风格。虽然具体的技术细节有所不同,但问题仍然存在——客户处理的是技术,而不是模型概念。诸如METADATA MAPPING LAYER这样的基础设施可以提供很大帮助,利用它很容易将查询结果转换为对象,但开发人员考虑的仍然是技术机制,而不是领域。更糟的是,当客户代码直接使用数据库时,开发人员会试图绕过模型的功能(如AGGREGATE,甚至是对象封装),而直接获取和操作他们所需的数据。这将导致越来越多的领域规则被嵌入到查询代码中,或者干脆丢失了。虽然对象数据库消除了转换问题,但搜索机制还是很机械的,开发人员仍倾向于要什么就去拿什么。

客户需要一种有效的方式来获取对已存在的领域对象的引用。如果基础设施提供了这方面的便利,那么开发人员可能会增加很多可遍历的关联,这会使模型变得非常混乱。另一方面,开发人员可能使用查询从数据库中提取他们所需的数据,或是直接提取具体的对象,而不是通过AGGREGATE的根来得到这些对象。这样就导致领域逻辑进入查询和客户代码中,而ENTITY和
VALUE OBJECT则变成单纯的数据容器。采用大多数处理数据库访问的技术复杂性很快就会使客户代码变得混乱,这将导致开发人员简化领域层,最终使模型变得无关紧要。

根据到目前为止所讨论的设计原则,如果我们找到一种访问方法,它能够明确地将模型作为焦点,从而应用这些原则,那么我们就可以在某种程度上缩小对象访问问题的范围。初学者可以不必关心临时对象。临时对象(通常是VALUE OBJECT)只存在很短的时间,在客户操作中用到它们时才创建它们,用完就删除了。我们也不需要对那些很容易通过遍历来找到的持久对象进行查询访问。例如,地址可以通过Person对象获取。而且最重要的是,除了通过根来遍历查找对象这种方法以外,禁止用其他方法对AGGREGATE内部的任何对象进行访问。

持久化的VALUE OBJECT一般可以通过遍历某个ENTITY来找到,在这里ENTITY就是把对象封装在一起的AGGREGATE的根。事实上,对VALUE的全局搜索访问常常是没有意义的,因为通过属性找到VALUE OBJECT相当于用这些属性创建一个新实例。但也有例外情况。例如,当我在线规划旅行线路时,有时会先保存几个中意的行程,过后再回头从中选择一个来预订。这些行程就是VALUE(如果两个行程由相同的航班构成,那么我不会关心哪个是哪个),但它们已经与我的用户名关联到一起了,而且可以原封不动地将它们检索出来。另一个例子是“枚举”,在枚举中一个类型有一组严格限定的、预定义的可能值。但是,对VALUE OBJECT的全局访问比对ENTITY的全局访问更少见,如果确实需要在数据库中搜索一个已存在的VALUE,那么值得考虑一下,搜索结果可能实际上是一个ENTITY,只是尚未识别它的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr___Ray

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值