Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oop 丰富的域模型-保护状态与方便映射_Oop_Domain Driven Design - Fatal编程技术网

Oop 丰富的域模型-保护状态与方便映射

Oop 丰富的域模型-保护状态与方便映射,oop,domain-driven-design,Oop,Domain Driven Design,我希望你能帮助我解决我和同事之间的一个小分歧 我一直认为,面向对象设计的原则是,对象应该保护其内部状态,并且只公开外部世界需要访问或更改的内容。在富域模型的上下文中,这意味着域对象应该强制执行它们所表示的模型的有效性,并且它们不应该允许外部调用方使它们的状态无效,即使它们是核心域对象并且没有直接暴露于外部世界 以Thing类型的对象为例,该对象具有一组属性。我的同事提出了以下建议 public class Thing { public List<ThingProperty>

我希望你能帮助我解决我和同事之间的一个小分歧

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

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

public class Thing 
{
    public List<ThingProperty> Properties { get; set; }
}
公共类的东西
{
公共列表属性{get;set;}
}
我不喜欢这样,因为它允许外部调用者将属性引用设置为null。他的辩护是,如果没有这种可变引用,很难从数据访问将数据加载到模型中,或者从表示层映射到核心模型

我的解决办法如下

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); }
}
公共类的东西
{
私有只读列表属性;
public Thing(){properties=new List();}
public ReadOnlyCollection{get{return properties.AsReadOnly();}
public void AddProperty(ThingProperty add){(validate)properties.add(add);}
}
这意味着在向对象添加属性时可能需要的任何验证都可以在模型内部进行验证(例如,如果只可以添加给定属性类型的一个实例),并且模型始终确保有效状态。缺点是很难将数据访问或表示模型映射到这种形式,但我认为这是值得付出的代价


有什么想法吗?谢谢。

你答对了,这就是DDD不变量的全部含义。通过使实体强制其自身的完整性(或聚合根强制其聚合的不变量),您可以确保域对象是完整的

“将数据加载到模型中”的论点是一个奇怪的论点,因为在您的示例中,加载一个无效的实体(一个“有两只眼睛的独眼巨人”或一个属性为null的
东西
)几乎没有什么价值

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

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

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

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

关于这个问题还有更详细的答案


域对象强制执行它们所表示的模型的有效性时,
属性
集合的实现就接近了

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