DDD系列-3

为什么要用Repository

实体模型与贫血模型

Entiry(实体)-ER模型:用来描述实体之间的关系,而后演变为一个数据模型,在关系数据库中代表了数据存储的方式。

许多ORM框架,忽略了Entiry本身行为,导致许多模型仅包含了实体数据(属性),而实体的业务逻辑被分散在多个服务、Controller、Utils工具类中–贫血模型

贫血模型特征
  • 大量的XxxDo对象:是数据库表结构的映射,里面没有包含(或包含了很少的)业务逻辑
  • 服务和Controller里有大量的业务逻辑:校验逻辑、计算逻辑、格式转化逻辑、对象关系逻辑、数据存储逻辑等;
  • 大量的Utils工具类
缺点
  • 无法保护模型对象的完整性和一致性
  • 象操作的可发现性极差
  • 代码逻辑重复
原因
  • 数据库思维:开发人员的思考方式就逐渐从**“写业务逻辑“转变为了”写数据库逻辑”**,也就是我们经常说的在写CRUD代码
  • 贫血模型“简单”:仅仅是对数据库表的字段映射
  • 脚本思维
核心原因
  • 数据模型(Data Model):指业务数据该如何持久化,以及数据之间的关系,也就是传统的ER模型;----只存在于数据层
  • 业务模型/领域模型(Domain Model):指业务逻辑中,相关联的数据该如何联动。----领域层

模型对象代码规范

1. 对象类型

1.1 Data Object(DO、数据对象)

DDD的规范里,DO应该仅仅作为数据库物理表格的映射,不能参与到业务逻辑中。

1.2 Entity(实体对象)

是我们正常业务应该用的业务模型,它的字段和方法应该和业务语言保持一致,和持久化方式无关。

1.3 DTO(传输对象)

主要作为Application层的入参和出参,比如CQRS里的Command、Query、Event,以及Request、Response等都属于DTO的范畴。DTO的价值在于适配不同的业务场景的入参和出参.

2.模型对象之间的关系

Do、Entiry、DTO不一定是1:1:1关系:

  • 复杂的Entity拆分多张数据库表:常见的原因在于字段过多,导致查询性能降低,需要将非检索、大字段等单独存为一张表,提升基础信息表的检索效率。
  • 多个关联的Entity合并一张数据库表:这种情况通常出现在拥有复杂的Aggregate Root - Entity关系的情况下,且需要分库分表,为了避免多次查询和分库分表带来的不一致性,牺牲了单表的简洁性,提升查询和插入性能。
  • 从复杂Entity里抽取部分信息形成多个DTO:这种情况通常在Entity复杂,但是调用方只需要部分核心信息的情况下,通过一个小的DTO降低信息传输成本。
  • 合并多个Entity为一个DTO:这种情况通常为了降低网络传输成本,降低服务端请求次数,将多个Entity、DP等对象合并序列化,并且让DTO可以嵌套其他DTO。

3.模型所在模块和转化器

在这里插入图片描述

3.1 DTO Assembler
  • 在Application层(可变)
  • 核心作用就是将1个多个相关联的Entity转化为1个或多个DTO
3.2 Data Converter
  • 在Infrastructure层(固件不易变)
  • Entity到DO的转化器没有一个标准名称,但是为了区分Data Mapper,我们叫这种转化器Data Converter。

4.Repository代码规范

传统Data Mapper(DAO)属于“固件”,和底层实现(DB、Cache、文件系统等)强绑定,如果直接使用会导致代码“固化”。所以为了在Repository的设计上体现出“软件”的特性,主要需要注意以下三点:

  • 接口名称不应该使用底层实现的语法: 我们常见的insert、select、update、delete都属于SQL语法,使用这几个词相当于和DB底层实现做了绑定。相反,我们应该把 Repository 当成一个中性的类似Collection 的接口,使用语法如 find、save、remove。
  • 出参入参不应该使用底层数据格式:Repository 操作的是 Entity 对象(实际上应该是Aggregate Root),而不应该直接操作底层的 DO 。更近一步,Repository 接口实际上应该存在于Domain层,根本看不到 DO 的实现。
  • 应该避免所谓的“通用”Repository模式

// 代码在Infrastructure层
@Repository // Spring的注解
public class OrderRepositoryImpl implements OrderRepository {
    private final OrderDAO dao; // 具体的DAO接口
    private final OrderDataConverter converter; // 转化器
    public OrderRepositoryImpl(OrderDAO dao) {
        this.dao = dao;
        this.converter = OrderDataConverter.INSTANCE;
    }
    @Override
    public Order find(OrderId orderId) {
        OrderDO orderDO = dao.findById(orderId.getValue());
        return converter.fromData(orderDO);
    }
    @Override
    public void remove(Order aggregate) {
        OrderDO orderDO = converter.toData(aggregate);
        dao.delete(orderDO);
    }
    @Override
    public void save(Order aggregate) {
        if (aggregate.getId() != null && aggregate.getId().getValue() > 0) {
            // update
            OrderDO orderDO = converter.toData(aggregate);
            dao.update(orderDO);
        } else {
            // insert
            OrderDO orderDO = converter.toData(aggregate);
            dao.insert(orderDO);
            aggregate.setId(converter.fromData(orderDO).getId());
        }
    }
    @Override
    public Page<Order> query(OrderQuery query) {
        List<OrderDO> orderDOS = dao.queryPaged(query);
        long count = dao.count(query);
        List<Order> result = orderDOS.stream().map(converter::fromData).collect(Collectors.toList());
        return Page.with(result, query, count);
    }
    @Override
    public Order findInStore(OrderId id, StoreId storeId) {
        OrderDO orderDO = dao.findInStore(id.getValue(), storeId.getValue());
        return converter.fromData(orderDO);
    }
}

转载总结自:
阿里技术专家详解DDD系列 第三讲 - Repository模式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
领域驱动设计(DDD)模型案例是一种将软件开发中的业务逻辑和领域专业知识相结合的方法。下面将以一个在线商城为例来说明领域设计的过程。 在一个在线商城的领域模型中,可以识别出多个核心领域对象,比如商品、订单、用户等。首先,我们需要明确每个领域对象的功能和属性。 在商品领域对象中,可以包含名称、描述、价格等属性,并具有一系列的行为,比如添加到购物车、下架商品等。同时,商品领域对象可能与分类、品牌等其他领域对象进行关联。 在订单领域对象中,可以包含订单号、购买商品、收货地址等属性。订单领域对象可能需要与用户、商品等其他领域对象进行关联,并具有一些行为,如支付订单、取消订单等。 用户领域对象可以包含用户ID、用户名、密码等属性,同时还可能需要与订单、购物车等其他领域对象进行关联。用户领域对象可以有一些行为,如注册用户、登录用户等。 此外,还可以识别出购物车、支付、物流等领域对象,并根据具体业务需求来设计它们的属性和行为。 在设计领域模型时,需要考虑到每个领域对象的内聚性、松耦合性以及其在整个系统中的关联关系。可以使用领域驱动设计中的聚合、实体、值对象、工厂等概念来进行模型设计。 在实际开发中,还需要与业务专家进行充分交流,深入了解业务需求和业务流程,确保领域模型的设计与实际业务需求一致,并通过不断验证和调整来优化模型。 总结起来,领域驱动设计模型案例的核心是识别并设计出符合业务需求的领域对象及其属性和行为,以及它们在系统中的关联关系。通过这样的设计,可以有效地解决业务问题,提高软件开发的质量和效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值