You need to enable JavaScript to run this app. DDD持久化映射:基于SOLID实现OrderDiscount领域对象的解耦映射
优惠活动
大模型
产品
解决方案
定价
更多

DDD持久化映射:基于SOLID实现OrderDiscount领域对象的解耦映射

符合DDD规范与SOLID原则的实体到领域折扣对象映射方案

现有方案的核心问题根因

原OrderMapper直接绑定单个具体OrderDiscountFactory实例,本质是把「折扣类型识别-工厂绑定」的硬编码逻辑放在基础设施层,直接违反:

  • 依赖倒置原则:Mapper直接依赖具体工厂实现,而非抽象匹配逻辑
  • 开闭原则:新增折扣类型时必须修改Mapper代码补充分支判断(即要求规避的switch逻辑)
  • 解耦要求:领域组件与基础设施层的映射逻辑强绑定,无法独立替换折扣实现

整体实现思路

依托已经定义的DiscountRegistry核心组件,通过「类型-工厂」的自动映射机制,完全消除分支判断,彻底解耦Mapper与具体折扣实现的依赖。

具体实现步骤

1. 修正领域层抽象契约

对现有OrderDiscountFactory接口补充最小必要契约,明确每个工厂的自描述能力,避免外部组件判断类型:

public interface OrderDiscountFactory {
    // 契约1:声明当前工厂支持的折扣类型,由每个实现类自行返回
    DiscountTypeEnum supportType();
    // 契约2:根据持久层存储的discountValue创建对应领域折扣对象
    OrderDiscount create(BigDecimal discountValue);
}

2. 强化DiscountRegistry的纯领域能力

将DiscountRegistry设计为无框架依赖的纯领域POJO,仅负责维护折扣类型-对应工厂的映射关系,不包含任何业务判断逻辑:

public class DiscountRegistry {
    // 内部存储映射关系,key为持久层存储的discountType枚举
    private final Map<DiscountTypeEnum, OrderDiscountFactory> factoryMapping = new HashMap<>();

    // 对外提供注册入口
    public void register(DiscountTypeEnum discountType, OrderDiscountFactory factory) {
        factoryMapping.put(discountType, factory);
    }

    // 对外提供工厂获取入口,全程无分支判断
    public OrderDiscountFactory getFactory(DiscountTypeEnum discountType) {
        OrderDiscountFactory factory = factoryMapping.get(discountType);
        if (factory == null) {
            throw new IllegalArgumentException("未匹配到对应折扣类型的工厂,类型值: " + discountType);
        }
        return factory;
    }
}

3. 基础设施层自动装配映射关系

在基础设施层实现注册表的自动初始化,完全避免手动编写分支判断收集工厂:

// 基础设施层自动配置组件(以Spring生态为例)
@Component
public class DiscountRegistryInitializer implements ApplicationRunner {
    private final DiscountRegistry discountRegistry;
    // 自动注入所有OrderDiscountFactory的实现类实例,无需手动列举
    private final List<OrderDiscountFactory> allFactories;

    @Override
    public void run(ApplicationArguments args) {
        // 遍历所有工厂,依靠工厂自身的supportType()方法完成注册
        allFactories.forEach(factory -> 
            discountRegistry.register(factory.supportType(), factory)
        );
    }
}

对应已实现的FixedAmountDiscount,补充其专属工厂实现:

@Component
public class FixedAmountDiscountFactory implements OrderDiscountFactory {
    @Override
    public DiscountTypeEnum supportType() {
        return DiscountTypeEnum.FIXED_AMOUNT;
    }

    @Override
    public OrderDiscount create(BigDecimal discountValue) {
        return new FixedAmountDiscount(discountValue);
    }
}

4. 重构OrderMapper的依赖关系

将原Mapper对具体工厂的直接依赖,替换为对抽象DiscountRegistry的依赖,彻底消除硬编码耦合:

@Repository
public class OrderMapperImpl {
    // 仅依赖抽象注册表,不感知任何具体折扣工厂的存在
    private final DiscountRegistry discountRegistry;

    // 构造器注入
    public OrderMapperImpl(DiscountRegistry discountRegistry) {
        this.discountRegistry = discountRegistry;
    }

    public Order toDomain(OrderEntity orderEntity) {
        // 直接读取持久层存储的两个字段
        DiscountTypeEnum discountType = orderEntity.getDiscountType();
        BigDecimal discountValue = orderEntity.getDiscountValue();
        // 通过注册表匹配对应工厂,全程无if/switch分支
        OrderDiscount orderDiscount = discountRegistry.getFactory(discountType).create(discountValue);
        // 组装Order聚合根
        return new Order(
            orderEntity.getOrderId(),
            orderEntity.getOriginalAmount(),
            orderDiscount
        );
    }
}

方案的规范符合性说明

  • 符合SOLID原则的要求:
    • 单一职责:Mapper仅负责实体与聚合根的转换,注册表仅负责类型与工厂的映射,每个工厂仅负责创建对应类型的折扣对象,无冗余职责
    • 开闭原则:后续新增折扣类型(如按比例折扣)时,仅需新增对应的OrderDiscount实现类、对应工厂类即可自动完成注册,无需修改Mapper、注册表的任何现有代码
    • 依赖倒置:Mapper依赖抽象的注册表组件,不依赖具体工厂实现;领域层不感知持久层的映射细节,依赖方向保持干净
    • 里氏替换:所有工厂实现只要符合接口契约,即可被注册表无缝替换,不影响现有逻辑运行
    • 接口隔离:工厂接口仅暴露必要的两个方法,无强制要求实现类完成的无关逻辑
  • 完全规避switch分支:所有类型匹配逻辑在应用启动时通过自动遍历完成,运行时仅做Map取值操作,无硬编码分支判断
  • 彻底解耦:原Mapper对单个工厂的强依赖被替换为抽象依赖链,任意折扣实现的调整不会影响Mapper的核心逻辑

注意点:保持领域层纯净,不要将框架依赖(如Spring的注解、自动配置逻辑)写入领域层的DiscountRegistry与OrderDiscountFactory接口,注册表的装配工作全部放在基础设施层完成。


内容的提问来源于stack exchange,提问作者F.M

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.29 18:54:05