【问题标题】:Rich domain models - protection of state vs convenience of mapping丰富的领域模型 - 状态保护与映射便利性
【发布时间】:2014-02-02 09:05:14
【问题描述】:

我希望你能帮助解决我与同事之间的轻微分歧。

我一直认为对象应该保护其内部状态并且只公开暴露外部世界需要访问或更改的内容是面向对象设计的原则。在富域模型的上下文中,这意味着域对象应该强制它们所代表的模型的有效性,并且它们不应该允许外部调用者使它们的状态无效,即使它们是核心域对象而不是直接调用暴露在外面的世界。

以 Thing 类型的对象为例,它具有一组属性。我的同事提出了以下建议。

public class Thing 
{
    public List<ThingProperty> Properties { get; set; }
}

我不喜欢这个,因为它允许外部调用者将属性引用设置为空。他的辩护是,如果没有这个可变引用,就很难将数据从数据访问加载到模型中,或者从表示层映射到核心模型。

我的解决方法如下...

public class Thing
{
    private readonly List<ThingProperty> properties;
    public Thing() { properties = new List<ThingProperty>(); }
    public ReadOnlyCollection<ThingProperty> { get { return properties.AsReadOnly(); } }

    public void AddProperty(ThingProperty add) { (validate) properties.Add(add); }
}

这意味着在向事物添加属性时可能需要的任何验证都可以在模型内部进行验证(例如,如果只添加给定属性类型的 1 个实例)并且模型始终确保有效状态。缺点是很难从数据访问或表示模型映射到这种形式,但我认为这是值得付出的代价。

有什么想法吗?谢谢。

【问题讨论】:

  • 如果域模型是您关心的问题,那么您的方法就是正确的方法。至于其他层,您之间只有单独的模型和映射。

标签: oop domain-driven-design


【解决方案1】:

你说得对,这就是 DDD 不变量 的全部意义所在。通过使实体强制执行它们自己的完整性(或聚合根对其聚合强制执行不变量),您可以确保您的域对象是 always valid

“将数据加载到模型中”的论点是一个奇怪的论点,因为 IMO 在加载无效实体方面几乎没有价值 - 在您的示例中,“有 2 只眼睛的独眼巨人”或带有空 PropertiesThing

当然,如果您的属性是只读的,您将无法访问内联对象初始化程序,但还有其他方便的方法可以一次性实例化实体(即有效的实体):构造函数、工厂、自定义生成器模式等。此外,如果您正在谈论从持久数据存储中重新水化域对象,大多数 ORM 都具有操作私有或受保护字段的能力,因此无需担心。

另请注意,函数式编程技术可能会使这更容易实现:immutability by default,不可为空的类型...

【讨论】:

    【解决方案2】:

    缺点是很难从数据访问或表示模型映射到这种形式

    但是您有一些选项可以简化从数据访问到域实体的映射

    How to retrieve Domain Object from Repositories有更详细的解答

    domain objects enforce the validity of the model they represent 时,您对Properties 集合的实现接近best practices for read-only lists implementation

    【讨论】:

      猜你喜欢
      • 2014-01-05
      • 1970-01-01
      • 2011-12-03
      • 1970-01-01
      • 2023-04-05
      • 1970-01-01
      • 1970-01-01
      • 2020-01-29
      • 1970-01-01
      相关资源
      最近更新 更多