首页 > 其他分享 >DDD | 05-什么是仓储层

DDD | 05-什么是仓储层

时间:2024-07-15 21:21:03浏览次数:15  
标签:聚合 05 对象 领域 订单 仓储 order DDD

四、什么是仓储层?

在DDD中,仓储(Repository)是一种设计模式,它充当了领域层与数据存储层之间的桥梁。仓储的主要职责是提供一种抽象机制,使得领域对象(尤其是聚合根)可以被透明地持久化和检索,而无需暴露底层的数据访问技术细节给领域层。这样设计的目的是为了保持领域模型的纯净性,让业务逻辑不受数据访问技术的影响,同时也促进了代码的可测试性和可维护性。

主要特点

接口定义在领域层

  • 仓储接口定义了诸如保存(save)、查找(find)、更新(update)和删除(delete)领域对象的方法,这些接口属于领域层从一部分,确保了领域逻辑的独立性

实现位于基础设施层

  • 虽然仓储接口属于领域层,但它的具体实现通常位于基础设施层(Infrastructure Layer)。实现细节回依赖于具体的持久化技术,如关系数据库、NoSQL数据库、内存数据库等

隔离领域层和数据访问层

  • 通过仓储模式,领域层的对象可以不知道也不关心数据是如何存储和检索的。这有助于降低各层之间的耦合度,使得领域逻辑更加集中和纯粹

提供一致的领域对象视图

  • 仓储还负责管理领域对象的生命期,确保从存储中检索出来的对象符合领域模型的规则,例如,确保聚合的一致性

支持领域驱动设计的原则

  • Ubiquitous Language(通用语言) 、业务优先和关注点分离等原则,通过仓储的抽象,可以更好地在代码中体现业务领域的概念和规则
问题探讨

仓储层和聚合根的区别是什么?

浅显解释

聚合根

  • 想象你有一个装满东西的盒子,这个盒子就是聚合根。盒子里的东西(比如小玩具、文具等)代表聚合内的其他实体和值对象。盒子外面有个标签,写着里面有什么,这就是聚合根的标识。当你相拿走或放回盒子里的东西是,必须通过盒子(聚合根)来做,不能直接对盒子里的物品动手脚。聚合根确保盒子里的东西按规则摆放,保持整齐(即业务规则的一致性)

仓储层

  • 想象有一个大仓库,里面存放着很多这样的盒子(聚合根)。仓库管理员(仓储层)知道怎么找到每一个盒子,并且能帮你把盒子放进仓库货从仓库里拿出来。你告诉管理员需要哪个盒子,管理员就会处理好一切,你不需要知道仓库是怎么排列这些盒子的,也不用管它是用叉车还是传送带搬运的(即数据访问的具体实现)

因此,聚合根是关于管理业务对象内部的规则和结构,而仓储层是关于如何保存和获取这些业务对象到数据存储中。聚合根关注"做什么",仓储层关注"怎么存取"。

术语解释

聚合根

  • 概念:聚合根是聚合中的一个特殊实体,它作为聚合的入口点,负责维护聚合内部的一致性。聚合是一组相关对象的集合,这些对象一起被当作一个单元来对待,对外界隐藏起内部结构和复杂性
  • 职责:聚合根确保所有的业务规则在聚合内部得到遵守,它控制着对聚合内其他实体和值对象的访问。外部对象不能直接访问聚合内的非根实体,只能通过聚合根进行操作
  • 示例:在一个电子商务系统中,订单Order可能是一个聚合根,它管理者订单项OrderItem、客户信息Customer等内部实体,确保例如订单总额的计算规则得到正确执行

仓储层

  • 概念:仓储是一个设计模式,它提供了一种抽象机制,用于透明地持久化和检索领域对象,尤其是聚合根。它就像是一个集合或数据库的模拟,允许领域层以面向对象的方式操作数据,而无需关心数据存储的具体细节
  • 职责:仓储的主要职责包括保存Save、查询Find、更新Update和删除Delete聚合根。它隔离了领域层和数据访问层,使得领域逻辑可以独立于具体的数据库技术
  • 示例:在一个电子商务系统中,OrderRepository可能提供方法来查找特定ID的订单、保存新订单到数据库、更新订单状态等,而不需要订单类知道这些操作是如何与数据库交互的

区别总结

  • 目的不同:聚合根关注于业务逻辑的封装和领域内的不变性维护,而仓储关注于领域对象的持久化和检索机制
  • 层次位置:聚合根是领域层的一部分,直接参与业务逻辑的实现;仓储虽然定义在领域层,但起具体实现通常位于基础设施层,作为领域层与数据存储之间的适配层
  • 交互方式:外部组件通过仓储来操作聚合根,而不会直接操作聚合内部的其他实体。聚合根则负责维护其内部状态和业务规则的一致性

简而言之,聚合根是领域模型中的核心构造,负责业务逻辑的实现和一致性保护;而仓储是领域层与数据存储之间的中介,确保领域对象能够被持久化和检索,同时保持领域模型的纯粹性

代码示例

写一个订单仓库 (OrderRepository)


public interface OrderRepository {

    /**
     * 保存订单聚合根。
     * @param order 待保存的订单聚合根对象,包含订单的所有相关信息。
     * @return 保存后的订单聚合根对象。
     */
    OrderAggregate save(OrderAggregate order);

    /**
     * 根据订单ID查找订单聚合根。
     * @param orderId 待查找订单的唯一标识。
     * @return 如果找到,则返回包含订单信息的Optional对象;否则返回空Optional。
     */
    Optional<OrderAggregate> findById(UUID orderId);

    /**
     * 删除订单聚合根。
     * @param order 待删除的订单聚合根对象。
     */
    void delete(OrderAggregate order);

    /**
     * 更新订单状态。
     * @param orderId 待更新订单的状态的唯一标识。
     * @param newStatus 新的订单状态信息。
     */
    void updateOrderStatus(UUID orderId, OrderStatusVO newStatus);
}


写一个基于内存的订单仓库实现类OrderRepositoryImpl

public class OrderRepositoryImpl implements OrderRepository {

    /**
     * 使用HashMap存储订单聚合体,以订单ID作为键,订单聚合体作为值。
     */
    private Map<UUID, OrderAggregate> orders = new HashMap<>();

    /**
     * 保存订单聚合体。
     *
     * @param order 要保存的订单聚合体。
     * @return 返回保存的订单聚合体。
     */
    @Override
    public OrderAggregate save(OrderAggregate order) {
        orders.put(order.getOrderId(), order);
        return order;
    }

    /**
     * 根据订单ID查找订单聚合体。
     *
     * @param orderId 要查找的订单ID。
     * @return 返回找到的订单聚合体的Optional,如果找不到则为empty。
     */
    @Override
    public Optional<OrderAggregate> findById(UUID orderId) {
        return Optional.ofNullable(orders.get(orderId));
    }

    /**
     * 删除订单聚合体。
     *
     * @param order 要删除的订单聚合体。
     */
    @Override
    public void delete(OrderAggregate order) {
        orders.remove(order.getOrderId());
    }

    /**
     * 更新订单状态。
     *
     * @param orderId       要更新状态的订单ID。
     * @param newStatus     新的订单状态。
     */
    @Override
    public void updateOrderStatus(UUID orderId, OrderStatusVO newStatus) {
        Optional<OrderAggregate> optionalOrder = findById(orderId);
        optionalOrder.ifPresent(order -> {
            order.changeStatus(newStatus);
        });
    }
}

OrderRepositoryImpl在DDD中所处位置?

属于基础设施层(Infrastructure Layer)的一部分。基础设施层提供技术性服务,如数据库访问、消息传递等,以支持领域层和应用层的功能。

具体分析,OrderRepository是一个接口,它定义了如何存取领域对象OrderAggregate到持久化存储(如数据库)中。这个接口属于领域层或核心域(Core Domain),因为它表达了领域逻辑的一部分需求,即如何管理订单聚合根的存储和检索。

OrderRepositoryImpl作为接口OrderRepository的一个实现,通常驻留在基础设施层。它实现了与具体数据存储技术(如JDBC、Hibernate、Spring Data JPA等)交互的细节,确保领域层可以透过一个抽象的接口与这些底层技术解耦。这样,领域层的代码就不需要关心数据是如何被存储或检索的,从而提高了代码的可维护性和灵活性。

标签:聚合,05,对象,领域,订单,仓储,order,DDD
From: https://www.cnblogs.com/dolphinmind/p/18303976

相关文章

  • DDD | 03-什么是实体对象
    二、什么是实体?实体(Entity)是一种核心的领域模型组件,用于表示具有唯一标识符、生命周期和行为的对象。实体是领域中关键概念的具体实例,它们通常对应于现实世界中的事物,比如用户、订单、账户等。主要特点唯一标识符(Identity):每个实体都有一个唯一的标识符,这个标识符是用来区......
  • DDD | 04-什么是聚合根
    三、什么是聚合根?聚合根(AggregateRoot)是DDD中的一个核心概念,用于组织和管理一组相关的领域对象,确保它们的整体一致性和完整性。聚合根是领域模型中的关键组件,它不仅封装了领域内的复杂业务逻辑,还提供了控制访问和维护数据一致性的机制,是构建可维护、可扩展的软件系统的重要基石......
  • DDD | 02-值对象拓展示例
    示例拓展金额和货币创建一个表示金额和货币的值对象(AmountVO),在系统中统一处理货币相关的数据,确保精度和一致性。importjava.math.BigDecimal;importjava.util.Currency;/***这个AmountVO类使用BigDecimal来精确存储金额值,避免了浮点运算可能带来的精度问题。同时,利用C......
  • 题解:SP10502 VIDEO - Video game combos
    大意构造一个长度为\(k\)(\(k\)是给定的)的串\(x\),使得对于\(∀1\leqi\leqn,s_i\)在\(x\)中的出现次数之和最大。输出这个最大值。思考考虑对\(s_i\)建AC自动机,然后dp。记\(dp[i][u]\)表示为长度为\(i\)的字符串,且当前已计算的节点是Trie上的编号为\(u......
  • 005_python3 元组 字典 集合 条件控制 循环语句 编程第一步
    Python3元组1.元组的元素不能修改,使用小括号,逗号隔开,也可不用小括号,不同类型元素tup1=()  #创建空元组tup2=('he',)   #元组中只包含一个元素时,需要在元素后面添加逗号 , ,否则括号会被当作运算符使用tup3=('abc','xyz',2,4,9)2.元组使用访问元组:tup3......
  • Java基础05:类型转换
    由于Java是强类型语言,所以要进行有些运算的时候的,需要用到类型转换。整型、实型(常量)、字符型数据可以混合运算。运算中,不同类型的数据先转化为同一类型,然后进行运算。转换从低级到高级(根据容量来看)。低------------------------------------------>高byte,short,char—>i......
  • 【DDD实战】ABP vNext框架
    ABPvNext配置1.模块化配置(AbpModule)可支持API、UI扩展可随意整合和拆分定制化需求——options模块整合下面是三种配置依赖模块的方式,分别是引用式、插件式、nuget1.引用式模块需引用dll配置步骤:模块依赖——DependsOn(typeof(___Module))需避免循环依赖配......
  • vue学习day05-watch侦听器(监视器)、Vue生命周期和生命周期的四个阶段、、工程化开发和
    13、watch侦听器(监视器)(1)作用:监视数据变化,执行一些业务逻辑或异步操作(2)语法:1)简写语法——简单数据类型,直接监视①Watch:{数据属性名(newValue,oldValue){一些业务逻辑或异步操作},‘对象·属性名’(newValue,oldValue){一些业务逻辑或异步操作}}②示例:结果:2)完整写法......
  • P9058 [Ynoi2004] rpmtdq
    前言开个巨坑,可能以后会三四天一更?分析路径考虑点分治,以下的\(dis\)皆为确定根节点的。以下点对\((i,j)\)都钦定\(dis_i\ledis_j\)注意到很多点对对答案是无用的,条件为若点对\((i,j)\)存在\(k\in[l+1,r-1]\),满足\(dis_i>=dis_k\or\dis_j\gedis_k\),则点对\((i,j)......
  • 【反悔贪心】P2949WorkSchedulingG+P4053[JSOI2007]建筑抢修题解
    这两天遇到了几个很神奇的题目——能反悔的贪心。赶紧记录一下。例1(用时一定模型)用时一定:每个任务完成的耗时都是一样的。题面:Luogu-P2949WorkSchedulingG大体思路是:先把所有任务按照截止时间从小到大排序,然后枚举,遇到一个能做任务的就把他做了,把他的贡献加入一个......