DDD设计方法-3-仓储,封装持久化数据

前情提要:一共包含 如下六篇文章(篇幅精简,快速入门)

1、初识DDD

2、聚合、实体、值对象

3、仓储,封装持久化数据

4、端口和适配器

5、领域事件

6、领域服务,实现约定

DDD设计方法-3-仓储,封装持久化数据

前言

面向对象的设计中,持久化数据的管理和访问是一个关键问题。为了解决这一问题,领域驱动设计(DDD)引入了仓储(Repository)模式。本文将深入探讨仓储模式的概念、作用以及如何实现和使用它来封装持久化数据。

1、概念 什么是仓储?

仓储模式是一种用于管理和访问持久化数据的设计模式。( 可以理解为更高抽象层次的mapper )

它通过提供一个抽象层,将数据存储的细节隐藏起来,使得上层业务逻辑不必直接与数据库交互,从而实现数据访问的解耦合。

2、优缺点 为什么要用?

先说缺点:

如果你的项目使用crud就非常清晰明了的可以完成你当前的业务 ,那么你引入这层会使你的代码量增加,且基本上属于 事倍功半。

优点:

1、解耦:

将业务逻辑与数据访问分离,提高代码的可维护性和可测试性。

2、易于替换:

由于仓储接口与其实现分离,更换不同的持久化技术时无需修改业务代码。

3、统一访问:

通过仓储模式,可以对数据访问进行统一管理,方便集中控制和优化。

3、和mapper到底什么区别?有关系吗?

相同点 :

1、都是涉及到数据库操作,负责从数据源获取数据,并将数据保存到数据源。

2、解耦:都旨在解耦业务逻辑和数据访问逻辑。

不同点

抽象级别:仓储模式通常在更高的抽象级别上工作,提供的是领域对象的集合操作接口,而Mapper更专注于单个对象与数据库记录之间的映射。
职责范围:仓储模式不仅包括数据映射,还包括业务相关的查询和操作逻辑;而Mapper主要关注对象与数据库之间的映射和简单的CRUD操作。
使用场景:仓储模式更多地在领域驱动设计(DDD)中应用,强调领域对象和持久化的隔离;而Mapper模式更适合直接操作数据库的场景,特别是当使用ORM框架时。

上边说的比较官方 ,我这边白话文在表格中解释一下

关于数据映射操作

mapper 数据映射 做简单的 CRUD 的
仓储模式(Repository Pattern) 前一篇文章我们理解过聚合的概念,可以吧那个思路带入进来,这个是针对多表复杂业务的统一 CRUD的 其中包含业务处理 !

同时由于仓储模式的数据操作时和业务聚合在一起的,

所以会带来另一个优点就是可以隐藏持久化的细节,在更换数据库类型的时候无需大量修改service

4、实例: 这里吧mapper 和 Repository 都写出来做个比较更直观一些

Mapper

定义Mapper接口

java 复制代码
public interface OrderMapper {
    void insertOrder(Order order);
    void updateOrder(Order order);
    void deleteOrderById(String orderId);
    Order selectOrderById(String orderId);

    // 其他与订单相关的CRUD操作
}

定义Mapper接口对应服务层

服务层A 既做订单的保存,又有删除。

java 复制代码
public class OrderServiceWithMapperA {
    private final OrderMapper orderMapper;

    public OrderServiceWithMapper(OrderMapper orderMapper) {
        this.orderMapper = orderMapper;
    }

    public void createOrder(Order order) {
        if (orderMapper.selectOrderById(order.getOrderId()) == null) {
            orderMapper.insertOrder(order);
        } else {
            orderMapper.updateOrder(order);
        }
        // 处理订单的历史记录、支付信息和物流信息等
        // 这里需要调用额外的Mapper对象来处理其他表的CRUD
        // orderHistoryMapper.insertOrUpdate(order.getHistory());
        // paymentInfoMapper.insertOrUpdate(order.getPaymentInfo());
        // shipmentInfoMapper.insertOrUpdate(order.getShipmentInfo());
    }

    public void deleteOrder(String orderId) {
        orderMapper.deleteOrderById(orderId);
        // 同时删除相关的订单历史记录、支付信息和物流信息等
        // orderHistoryMapper.deleteByOrderId(orderId);
        // paymentInfoMapper.deleteByOrderId(orderId);
        // shipmentInfoMapper.deleteByOrderId(orderId);
    }

    public Order getOrder(String orderId) {
        return orderMapper.selectOrderById(orderId);
    }
}

服务层B 只做订单的保存。

java 复制代码
public class OrderServiceWithMapperB {
    private final OrderMapper orderMapper;

    public OrderServiceWithMapper(OrderMapper orderMapper) {
        this.orderMapper = orderMapper;
    }

    public void createOrder(Order order) {
        if (orderMapper.selectOrderById(order.getOrderId()) == null) {
            orderMapper.insertOrder(order);
        } else {
            orderMapper.updateOrder(order);
        }
        // 处理订单的历史记录、支付信息和物流信息等
        // 这里需要调用额外的Mapper对象来处理其他表的CRUD
        // orderHistoryMapper.insertOrUpdate(order.getHistory());
        // paymentInfoMapper.insertOrUpdate(order.getPaymentInfo());
        // shipmentInfoMapper.insertOrUpdate(order.getShipmentInfo());
    }

    public Order getOrder(String orderId) {
        return orderMapper.selectOrderById(orderId);
    }
}

Repository

定义仓储接口

java 复制代码
import java.util.Optional;

public interface OrderRepository {
    void saveOrder(Order order);
    void deleteOrder(String orderId);
    Optional<Order> findOrderById(String orderId);
}

实现仓储接口

java 复制代码
public class OrderRepositoryImpl implements OrderRepository {
    private final OrderMapper orderMapper;

    public OrderRepositoryImpl(OrderMapper orderMapper) {
        this.orderMapper = orderMapper;
    }

    @Override
    public void saveOrder(Order order) {
        if (orderMapper.selectOrderById(order.getOrderId()) == null) {
            orderMapper.insertOrder(order);
        } else {
            orderMapper.updateOrder(order);
        }
        // 处理订单的历史记录、支付信息和物流信息等
        // orderHistoryMapper.save(order.getHistory());
        // paymentInfoMapper.save(order.getPaymentInfo());
        // shipmentInfoMapper.save(order.getShipmentInfo());
    }

    @Override
    public void deleteOrder(String orderId) {
        orderMapper.deleteOrderById(orderId);
        // 同时删除相关的订单历史记录、支付信息和物流信息等
        // orderHistoryMapper.deleteByOrderId(orderId);
        // paymentInfoMapper.deleteByOrderId(orderId);
        // shipmentInfoMapper.deleteByOrderId(orderId);
    }

    @Override
    public Optional<Order> findOrderById(String orderId) {
        return Optional.ofNullable(orderMapper.selectOrderById(orderId));
    }
}

使用仓储模式的服务层

两处仓储的服务层代码基本一致 全为调用 仓储接口

java 复制代码
public class OrderService {
    private final OrderRepository orderRepository;

    public OrderService(OrderRepository orderRepository) {
        this.orderRepository = orderRepository;
    }

    public void createOrder(Order order) {
        orderRepository.saveOrder(order);
    }

    public void deleteOrder(String orderId) {
        orderRepository.deleteOrder(orderId);
    }

    public Order getOrder(String orderId) {
        return orderRepository.findOrderById(orderId).orElseThrow(() -> new RuntimeException("Order not found"));
    }
}

这里简单说下两者写法的区别和使用仓储模式的好处

职责分离:

Mapper:直接与数据库表交互,完成基本的CRUD操作。服务层需要调用多个Mapper以处理复杂的业务逻辑。

仓储模式:仓储模式在Mapper之上添加了一层抽象,将复杂的业务逻辑封装在仓储实现中,服务层只需调用仓储接口即可。

代码简洁性:

Mapper:由于直接操作数据库,服务层可能会变得复杂,需要处理多个Mapper的调用逻辑。

仓储模式:将复杂的业务逻辑封装在仓储层,服务层代码更加简洁和聚焦。

可维护性:

Mapper:当业务逻辑变更时,服务层可能需要修改大量代码。

仓储模式:业务逻辑集中在仓储层,更容易管理和维护。

扩展性:

Mapper:更换持久化技术时,需要修改所有涉及数据访问的地方。

仓储模式:只需修改仓储的实现部分,服务层无需变动。

相关推荐
weixin_5375904515 分钟前
《Java编程入门官方教程》第八章练习答案
java·开发语言·servlet
CodeClimb41 分钟前
【华为OD-E卷-最左侧冗余覆盖子串 100分(python、java、c++、js、c)】
java·python·华为od
Q_19284999061 小时前
基于Spring Boot的大学就业信息管理系统
java·spring boot·后端
xmh-sxh-13141 小时前
常用数据库类型介绍
java
single5941 小时前
【c++笔试强训】(第四十一篇)
java·c++·算法·深度优先·图论·牛客
1 9 J1 小时前
Java 上机实践11(组件及事件处理)
java·开发语言·学习·算法
爬菜2 小时前
java简单题目练习
java
bufanjun0012 小时前
JUC并发工具---ThreadLocal
java·jvm·面试·并发·并发基础
南宫生2 小时前
力扣-图论-70【算法学习day.70】
java·学习·算法·leetcode·图论