DDD:概念一致但验证规则不同的共享Value Object如何设计?
我已经阅读过两个关于DDD值对象的相关讨论,当值对象(VO)可以完全共享时,这些内容都合理。
我现在的场景是多个领域实体都用到“名称”这个值对象概念,当前的代码实现如下:
public record Name { public string Value { get; } private const uint MinLength = ValidationConstants.MinNameLength; private const uint MaxLength = ValidationConstants.MaxNameLength; public Name(string value) { value = value.Trim(); if (!value.LengthIsBetween(MinLength, MaxLength)) { throw new InvalidResourceNameException( $"Name must be provided and be between {MinLength} and {MaxLength} characters (inclusive)" ); } Value = value; } }
但不同实体对名称的最小/最大长度限制不一样。我可以在构造Name时传入长度参数,但觉得这样不符合VO应该维护自身不变量的原则(如果我的理解有误请指正)。
请问哪种方案更符合DDD理念:是为每个实体单独定义对应的Name VO,还是先定义一个基础Name VO,再扩展出满足各实体特定需求的VO,比如:
public record EntityName : Name { // 实体特定逻辑 }
首先明确核心原则:值对象的不变量必须内聚且固定——它代表领域中一个明确的概念,约束条件是这个概念本身的固有属性,而非依赖外部传入的参数。所以构造时传入长度参数的方案确实不符合DDD中VO的设计原则,这会让VO的不变量失去确定性,违背了值对象作为领域概念载体的意义。
针对两种可选方案分析如下:
1. 为每个实体单独定义专属的Name VO
这是最贴合DDD理念的方案。不同实体的“名称”在业务语境中本质是不同的领域概念:比如CustomerName和ProductName,长度限制的差异源于它们在业务中的定位——客户名称可能需要容纳更多字符,产品名称则要求简洁易识别。每个专属VO维护自身固定的不变量,清晰对应特定领域概念,避免共享带来的歧义,同时提升代码的可读性和维护性。
示例代码:
public record CustomerName { public string Value { get; } private const uint MinLength = 2; private const uint MaxLength = 50; public CustomerName(string value) { value = value.Trim(); if (!value.LengthIsBetween(MinLength, MaxLength)) { throw new InvalidCustomerNameException( $"客户名称长度必须在{MinLength}到{MaxLength}字符之间(包含边界值)" ); } Value = value; } } public record ProductName { public string Value { get; } private const uint MinLength = 1; private const uint MaxLength = 20; public ProductName(string value) { value = value.Trim(); if (!value.LengthIsBetween(MinLength, MaxLength)) { throw new InvalidProductNameException( $"产品名称长度必须在{MinLength}到{MaxLength}字符之间(包含边界值)" ); } Value = value; } }
2. 继承基础Name VO扩展专属VO
这种方案需谨慎使用。DDD中值对象强调值的相等性,继承很可能破坏这一语义——比如EntityName和Name实例的相等性判断会出现不符合预期的结果。此外,基础VO若承载通用逻辑,容易演变成模糊领域边界的“万能抽象”。即便要采用这种方式,也必须确保基础VO仅提供纯通用工具方法(如字符串修剪),不变量完全由子类定义,但这种做法的收益远不如单独定义VO清晰。
总结:优先选择为每个实体定义专属的Name值对象,这最贴合DDD“值对象对应明确领域概念”的核心思想,让领域规则的表达更清晰、内聚。
内容的提问来源于Stack Exchange,提问作者Ruben Hart

