资源库

资源库(Repository)是对数据访问的一种业务抽象,使其具有业务意义。利用资源库抽象,就可以解耦领域层与外部资源,使领域层变得更为纯粹,能够脱离外部资源而单独存在。注意,仓储接口的定义是在领域层,但是它的实现是在Infrastructure层。引入仓储的好处或者说目标就是让业务逻辑层只关注业务层的逻辑,而不需要关注具体的存储层技术的实现。

之所以引入资源库,主要目的还是为了管理聚合的生命周期。工厂负责聚合实例的生,垃圾回收负责聚合实例的死,资源库就负责聚合记录的查询与状态变更,即记录的“增删改查”操作。不同于活动记录(Active Record)模式,资源库分离了聚合的领域行为和持久化行为。为了更好地管理聚合,领域驱动设计对资源库的设计做了一定程度的限制与规范。

一个聚合对应一个资源库

聚合只有一个入口,那就是聚合根;对聚合生命周期的管理,也只有一个入口,那就是聚合对应的资源库。要访问聚合内的其他实体和值对象,也只能通过聚合对应的资源库进行,这就保护了聚合的封装性。一言以蔽之:通过资源库获取聚合的引用,通过对象图的单一遍历方向获得聚合内部对象。例如,要为订单添加订单项,这样的做法就是错误的:

OrderItemRepository oderItemRepo;

orderItemRepo.add(orderId, orderItem);

OrderItem 不是聚合,不能为其定义资源库。OrderItem 是 Order 聚合的内部实体,因此添加订单项的操作本质上是更新订单的操作:

OrderRepository orderRepo;

Order order = orderRepo.orderOfId(orderId);
order.addItem(orderItem);

orderRepo.update(order);

添加订单项功能由 Order 聚合根实体实现,addItem() 方法的实现可以保证订单领域概念的完整性,实现不变量。例如,该方法可以根据 OrderItem 中的 ProductId 来判断究竟是添加订单项,还是合并订单项,然后修改订单项中所购商品的数量。

资源库的领域特征

1、避免适用和具体的底层存储相关的方法名称:

比如使用save方法,而不insert和update。因为对于业务而言,我关心的就是把模型的数据持久化就好了,业务不关心到底是插入还是更新。

2、方法入参和返回值都要使用领域层的模型对象,不要使用底层的数据层对象。

代码示例

/**
 * 用户-Repository接口
 *
 * @author haoxin
 * @date 2021-02-02
 **/
public interface UserRepository {

    /**
     * 通过用户ID获取用户
     *
     * @param userId
     * @return
     */
    User find(UserId userId);

    /**
     * 根据token获取用户
     *
     * @param token
     * @return
     */
    User find(Token token);

    /**
     * 根据手机号获取账号
     *
     * @param mobile
     * @return
     */
    List<User> find(Mobile mobile);

    /**
     * 保存
     *
     * @param user
     */
    UserId store(User user);

    /**
     * 删除
     *
     * @param userIds
     */
    void remove(List<UserId> userIds);
}

results matching ""

    No results matching ""