You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DDD战术建模:促销系统多实体判定及代码复用方案咨询

促销系统领域建模问题解答

一、判定是否正确:是正确的

在DDD领域战术建模中,聚合根的划分核心依据是业务规则的一致性边界。四种促销类型各自拥有独特的业务规则(比如满减、折扣、赠品、满赠的生效逻辑、计算规则完全不同)、差异化数据(如满减的门槛金额、折扣的折扣率),这些规则和数据需要独立的一致性校验和生命周期管理,因此将它们划分为不同的聚合根/实体是完全符合DDD原则的。

二、实现代码与共享属性复用的建模方案

1. 抽象基类封装通用属性与行为

将所有促销共享的属性(Name、Description、促销周期)和通用行为(如校验有效期、获取基础信息)封装到抽象基类中,具体促销类型继承该基类并实现自身独有的业务逻辑。

示例代码(C#):

// 抽象基类:通用促销属性与行为
public abstract class Promotion
{
    public string Name { get; protected set; }
    public string Description { get; protected set; }
    public PromotionPeriod Period { get; protected set; }

    // 通用行为:判断促销是否处于有效期内
    public bool IsActive()
    {
        var now = DateTime.UtcNow;
        return Period.InitialDate <= now && now <= Period.FinalDate;
    }

    // 抽象方法:每个促销必须实现的核心业务逻辑(比如计算优惠)
    public abstract decimal CalculateDiscount(Order order);
}

// 值对象:封装促销周期及校验逻辑
public record PromotionPeriod(DateTime InitialDate, DateTime FinalDate)
{
    // 工厂方法:确保日期合法性
    public static PromotionPeriod Create(DateTime initial, DateTime final)
    {
        if (initial > final)
            throw new InvalidOperationException("促销起始日期不能晚于结束日期");
        return new PromotionPeriod(initial, final);
    }
}

2. 值对象复用共享属性组合

把具有业务含义的共享属性组合封装为值对象(比如上面的PromotionPeriod),所有促销类型直接复用该值对象,避免重复编写日期校验等逻辑,同时保证属性的一致性。

3. 领域服务提取跨聚合通用行为

如果存在多种促销都需要的通用行为(比如促销状态变更通知、促销规则的通用校验逻辑),不要将这些逻辑放到基类中,而是抽离为独立的领域服务,让各个聚合根调用该服务完成操作。

示例:

public class PromotionCommonService
{
    public void LogPromotionUsage(Promotion promotion, Order order)
    {
        // 通用日志记录逻辑,所有促销类型都可调用
        Console.WriteLine($"促销[{promotion.Name}]已应用于订单[{order.OrderId}]");
    }
}

4. 策略模式处理可变业务规则

对于某些可抽象的可变规则(比如优惠计算、资格校验),可以用策略模式将规则逻辑与聚合根分离。基类定义统一的规则调用接口,具体促销类型注入对应的策略实现,既保持聚合根的独立性,又能复用规则调用的逻辑框架。

示例:

// 优惠计算策略接口
public interface IDiscountCalculationStrategy
{
    decimal Calculate(Order order, Promotion promotion);
}

// 满减策略实现
public class FullReductionStrategy : IDiscountCalculationStrategy
{
    public decimal Calculate(Order order, Promotion promotion)
    {
        var fullReductionPromo = promotion as FullReductionPromotion;
        if (fullReductionPromo == null || !promotion.IsActive()) return 0;
        return order.TotalAmount >= fullReductionPromo.Threshold ? fullReductionPromo.ReductionAmount : 0;
    }
}

// 聚合根中注入策略
public class FullReductionPromotion : Promotion
{
    private readonly IDiscountCalculationStrategy _calculationStrategy;
    public decimal Threshold { get; private set; }
    public decimal ReductionAmount { get; private set; }

    public FullReductionPromotion(string name, string description, PromotionPeriod period, decimal threshold, decimal reductionAmount, IDiscountCalculationStrategy calculationStrategy)
    {
        Name = name;
        Description = description;
        Period = period;
        Threshold = threshold;
        ReductionAmount = reductionAmount;
        _calculationStrategy = calculationStrategy;
        Validate();
    }

    public override decimal CalculateDiscount(Order order)
    {
        return _calculationStrategy.Calculate(order, this);
    }
}

注意事项

  • 基类只保留真正通用的属性和行为,避免过度抽象导致基类臃肿(比如不要把某几种促销特有的逻辑强行放到基类);
  • 每个聚合根保持自身业务逻辑的完整性,内部状态的修改仅由自身方法控制,不依赖其他聚合根;
  • 避免在基类中引入外部依赖(比如数据库、第三方服务),这类逻辑应放到领域服务或基础设施层。

内容的提问来源于stack exchange,提问作者raphael-melo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 08:25:20