为什么使用资源库?
如果完全按照领域模型的角度,完全通过遍历对象的方法来获取所有关联的对象。这种模型会过于错综复杂。对象嵌套的层级或者关联的层级非常深。例如通过 Customer.order.product.price 层层遍历来获取当时客户订单的商品的价格。
那如果完全按照数据库模型的角度,模型中的对象不需要完全连接起来,对象关系网就能保持在一个可控范围。但是这又会回到之前传统开发模式中,零散的使用各个 DAO 从各个表抽取数据自行拼凑出我们想要的模型。
这里就会出现一个问题,Customer 类需要保持客户所有已订的 Order,还是通过 CustomerID 在数据库中查找 Order 列表呢?
对象关联还是纯数据库?
客户需要一种有效的方式来获取已存在的领域对象的引用。如果基础设施提供了这方面的遍历,那么开发人员可能会增加很多可遍历的关联,这会使模型变得非常混乱。另一方面,开发人员可能使用查询从数据库中提取他们所需的数据,或是直接提取具体的对象,而不是通过聚合的根来得到这些对象。这样就导致领域逻辑进入查询和客户代码中,而实体和值对象变成了单纯的数据容器。采用大多数处理数据库访问的技术复杂性很快就会使客户代码变得混乱,这将导致开发人员简化领域层,最终使模型变得无关紧要。
我们需要找到一个恰当的方式。
我们不需要对那么很容易通过遍历来找到的持久对象进行查询访问,如不需要单独的去获取地址,而可以通过 Person 对象来获取地址,意味着当我们获取 Person 对象的时候,地址值对象已经是填充好的。我们不需要特地利用另外一个资源库的方法,获取地址再进行填充。但当获取 Person 的所有订单记录时,由于订单的数量有时候过于庞大,加载 Person 的时候其实并不一定需要查看订单记录,我们应该使用 Repository 的另外方法来获取 Person 的订单记录。
对值对象的全局搜索通常是没有意义的。如果确实需要在数据库中搜索一个已知的值对象,那么值得考虑一下,搜索结果可能实际上是一个实体,尚未识别出它的标识。
定义
在所有持久化对象中,有一小部分必须通过基于对象属性的搜索来全局访问。当很难通过遍历的方式来访问某些聚合根的时候,就需要这种访问方式,它们通常是实体,有时可能是具有复杂内部结构的值对象。而其他对象则不适合使用这种访问方式,因为这会混淆它们之间的重要区别。随意的数据库查询会破坏领域对象的封装和聚合。技术基础设施的数据访问机制的暴露会增加客户的复杂度,并妨碍模型驱动的设计。
如何使用资源库
我们应该将资源库看作一个对象的集合。
客户使用查询方法向资源库请求对象,这些查询方法根据客户所指定的条件来挑选对象。资源库检索被请求的对象,并封装数据库查询和元数据映射机制。他们可以返回汇总的信息,如多少个实例满足条件。甚至返回汇总计算,如所有匹配对象的某个数值属性的总和。
这样一来客户就只需与一个简单的、易于理解的接口进行对话,并根据模型向这个接口提出它的请求。
为每种需要全局访问的对象类型创建一个资源库,这个资源库相当于该类型的所有对象在内存的一个集合的“替身”。通过一个众所周知的全局接口来提供访问。提供添加和删除对象的方法,用这些方法来封装在数据存储中实际插入和删除数据的操作。根据提供具体条件来挑选对象的方法,并返回属性值满足条件的对象或者对象集合,从而将实际的存储和查询技术封装起来。只为那些确实需要直接访问的聚合根提供资源库,让客户始终聚焦于模型,而将所有对象的存储和访问操作交给资源库来完成。
让用户无感知的,以为就在内存中使用一个集合一样。
资源库的方法设计:
方法参数:
- 唯一标识
- 复杂的参数组合
- 值域(日期范围)
返回值:
- 对象
- 对象集合
- 某些类型的汇总。
资源库的实现
- 对类型进行抽象,比如有奔驰车宝马车,不应有两种资源库,而应该是只有一个抽象车类的资源库。
- 充分利用与客户进行解耦。
- 将事务的控制权交给客户。
资源库的优点
- 为客户提供了一个简单的模型,可用来获取持久化对象并管理他们的生命周期。
- 他们将应用程序和领域设计与持久化技术进行解耦。
- 它们体现了有关对象访问的设计决策。
- 很容易测试,将利用集合直接替换资源库进行测试。
资源库中如何管理事务
对事务的管理绝对不应该放在领域模型和领域层中。通常来说,与领域模型相关的操作都非常的细粒度,以致于无法用于管理事务。另外,领域模型也不应该意识到事务的存在。通常我们将事务放在应用层,然后为每个主要的用例创建一个门面,一个用例对应一个门面业务方法,如果所有操作安全完成的话,门面中的业务方法提交事务,否则失败回滚。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于