2009-08-26 356 views
9

比方说,我有典型的实体汽车DDD:亚类根实体

class Car : Entity 
{ 
    public double MaxSpeed { get; set; } 
    public Color Color { get; set; } 
    /* ... */ 
} 

这个实体,在我的域模型,将是一个聚合根实体

现在让我们说我专注于汽车。我创建了一个法拉利,和法拉利的车主高兴通过像一个绰号叫他们:

class Ferrari : Car 
{ 
    public string Nickname { get; set; } 
} 

比方说,我有另外一个实体,在公司实体。这将是根实体的另一个总计。有很多人在一家公司工作,由实体代表。人可能有汽车。但公司的总统通常是非常丰富,这样的人,他们有法拉利:

class President : Person 
{ 
    public Ferrari Ferrari { get; set; } 
} 

在这种情况下,我有实体总统,谁是公司汇总,这是持有一个法拉利的参考,专业化的另一个聚合的根实体。

鉴于DDD,这是否正确?可以/我应该考虑将根实体本身作为同一个聚合的根实体吗?我的意思是,在我所描述的领域中,实体法拉利也是汽车总成的根本实体(因为法拉利也是汽车)?


现在,让我们说,我要坚持这个模型到数据库。我认为我的问题不依赖于我将使用的OR/M框架。

我应该如何建造桌上持有汽车?我是否应该建立一个带有“CarType”列的Cars Cars(可能的值:“Car”,“Ferrari”)和一个可以为空的昵称列?

或者我应该为Cars创建一张桌子,为Ferraris创建一个桌子,后者的PK有FK的Cars?

谢谢!

回答

2

我认为你通过创建这些实体的具体类型而开始丧失很多系统的灵活性。您暗示的关系类型通常是我通常使用的“类型”实体。例如,你有一辆车。法拉利是一种汽车。由此产生的两个实体是Car和CarType。

你正在谈论这样做的方式,每次引入新类型时都必须添加新实体。如果你试图捕捉的所有东西都是汽车的“绰号”,那么我认为那只是另一部分数据,而不是另一个实体。除非你有不同的数据(即不同的属性名称)和/或不同类型的汽车实体的行为差异,这种方法不会获得太多收益。我宁愿使用像FindCarByType()这样的存储库方法来处理一种类型的实体,以降低风险。

我绝不是DDD专家,而我正在为一些概念而奋斗(或者更像是在对一些概念的多重解释中挣扎)。我发现没有100%纯粹的实现,并且我看到每个实现都有细微差别。

编辑遵循

我看到,我误解你写哪一部分。我看到这个绰号并非针对所有车辆,而是针对法拉利:车。我认为答案确实“取决于”。你在模型的其余部分有多少专业领域?拥有一个绰号可能在法拉利实体中流行,但是它是排他性的吗?它不仅关于实际数据,而且关于要求。基本上,这取决于您在这些实体中期望的专业化程度。

+0

太棒了!谢谢!事实上,在我的“真实”系统中,“汽车”是非常重要的,但“法拉利”是我的领域中唯一最重要的东西,我不能疏忽跟踪,我必须对其进行统计。 – 2009-08-29 21:55:43

4

您不应该使用继承来为您的域建模,因为一旦模型开始变得复杂,您很快就会遇到麻烦。

总统只是一个角色,人和人可以有多个角色。也许总统只有一个角色,但选择错误的例子只是偶然的。

法拉利不应该从汽车继承。在法拉利的例子中并不明显,因为他们只做一种类型的汽车,但考虑制造各种类型的公司,如厢式货车,轿车,掀背车,卡车等。您可能会想要为从汽车类继承的每种类型创建类。然后,你会做出五种丰富的类别,从每种类型继承下来吗?如...

Car -> Sedan -> ToyotaSedan 
Car -> Truck -> ToyotaTruck 
Car -> Hatchback -> ToyotaHatchback 

这将是荒谬的。

声明:我对汽车一无所知。但是...

不要使用继承来为您的域建模。永远。

尝试没有继承,它也将成为显而易见的如何坚持你的域名。

+0

谢谢,卢博斯。但在这种情况下,在我的“真实”领域,我*有*“汽车”,并且有“通用”汽车和两种特殊类型的汽车,“法拉利”和“保时捷”必须被追踪,尽管它们是基本上是“汽车”。 – 2009-08-29 21:58:19

+3

还是要避免继承。即使你不这样做,你也需要在一两年内完成,因为你的模型未来可能会变得更加复杂以捕捉新的需求,并且继承会给你的设计带来很大的痛苦。教科书中解释猫和狗的遗传的例子都是动物和圆形和方形都是形状给人错误的印象什么是继承真正的,程序员经常滥用这个强大的概念来建模域。阅读更多在这里:http://www.geocities.com/tablizer/oopbad.htm#overeng(我不是作者) – 2009-08-29 22:42:28

+0

非常好的文章!谢谢! – 2009-08-29 23:02:31

3

通常,当您跨越根集合边界时,只允许引用是另一个根集合的ID。然后使用该ID在其存储库中查找另一个聚合。

所以在你的情况下,你会希望总统有一个车号,如果你需要对总统的车做些什么,你可以使用车号到车库去取车。总统不会提及汽车本身。

现在关于那辆法拉利。在标准的DDD术语中执行这种操作是很困难的。通常情况下,你会对分配给总统的汽车进行一些验证。或者可能有一个只为总统提供的CarBuyingService服务,以确保您的服务是正确的。通常在DDD专业本身并不是根本的总和。

+0

你是唯一真正回答问题的人 – 2017-11-27 22:55:53