DDD:子类和根实体
假设我有典型的实体Car
class Car : Entity
{
public double MaxSpeed { get; set; }
public Color Color { get; set; }
/* ... */
}
,在我的域模型中,该实体将是聚合的根实体强>。
现在假设我专门研究汽车。我创建了一辆法拉利,法拉利的快乐车主喜欢用昵称来称呼它们:
class Ferrari : Car
{
public string Nickname { get; set; }
}
假设我有另一个实体,公司实体。它将是另一个聚合的根实体。有很多人在公司工作,由实体 Person 表示。人们可能有汽车。但是公司的总裁通常非常富有,而且这种人,他们有法拉利:
class President : Person
{
public Ferrari Ferrari { get; set; }
}
在这种情况下,我有实体总裁,他在里面 公司聚合,它包含对 Ferrari 的引用,是另一个聚合的根实体的专业化。
鉴于 DDD,这是正确的吗?我可以/应该将根实体本身的专业化视为同一聚合的根实体吗?我的意思是,在我描述的领域中,法拉利实体也是汽车聚合的根实体(因为法拉利也是汽车)吗?
现在假设我必须将此模型保留到数据库。我认为我的问题并不取决于我将使用的 OR/M 框架。
我应该如何构建存放汽车的桌子?我应该构建一个带有“CarType”列(可能的值:“Car”、“Ferrari”)和可为空的 Nickname 列的单个表 Cars 吗?
或者我应该为汽车建立一张桌子,为法拉利建立一张桌子,后者的 PK 是汽车的 FK?
谢谢!
Let's say I have the typical entity Car
class Car : Entity
{
public double MaxSpeed { get; set; }
public Color Color { get; set; }
/* ... */
}
This entity, in my domain model, would be the root entity of an Aggregate.
Now let's say I specialize cars. I create a Ferrari, and the happy owners of Ferraris like to call them by a nickname:
class Ferrari : Car
{
public string Nickname { get; set; }
}
Let's say I have another entity, the Company entity. It would be the root entity of another Aggregate. There are many people working on a company, represented by the entity Person. Persons may have cars. But the President of a company is usually very rich and this kind of people, they have Ferraris:
class President : Person
{
public Ferrari Ferrari { get; set; }
}
In this situation, I have the entity President, who is inside the Company Aggregate, that is holding a reference to a Ferrari, an specialization of the root entity of another aggregate.
Is this correct in view of DDD? Can/should I consider the specialization of root entities themselves as root entities of the same aggregate? I mean, in the domain I described, is the entity Ferrari also the root entity of the Car Aggregate (since Ferrari is also a Car)?
Now let's say I have to persist this model to a Database. I think that my question does not depend on the OR/M framework I will use.
How should I build the table holding Cars? Should I build a single table Cars, with a "CarType" column (possible values: "Car", "Ferrari"), and a nullable Nickname column?
Or should I build a table for Cars and a table for Ferraris, the latter one having its PK a FK of Cars?
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
通常,当您跨越根聚合边界时,您只允许引用其他根聚合的 ID。然后,您可以使用该 ID 在其存储库中查找其他聚合。
因此,在您的情况下,您希望总统拥有一个汽车 ID,如果您需要对总统的汽车执行某些操作,您将使用汽车 ID 前往存储库获取汽车。总统不会提及汽车本身。
现在说说那辆法拉利。用标准 DDD 术语来强制执行这一点有点困难。通常,您会对向总统分配汽车进行一些验证。或者也许有专为总统提供的汽车购买服务,可确保您正确购买。通常,在 DDD 中,专业化本身并不是根聚合。
Generally when you cross root aggregate boundaries you only allow the reference to be of the ID of the other root aggregate. You then use that ID to look up the other aggregate in its repository.
So in your case you would want President to have a Car ID and if you ever needed to do something to the President's car you would use the Car ID to go to the repository to get the car. President would not have a reference to the Car itself.
Now about that Ferrari. It's kind of difficult to enforce that in standard DDD terminology. Normally you would put some validation on the assignment of a Car to a President. Or perhaps there is a CarBuyingService just for Presidents that makes sure you get it right. Normally in DDD specializations are not themselves root aggregates.
您不应该使用继承来对您的域进行建模,因为一旦模型开始变得复杂,您很快就会遇到麻烦。
总统只是一个人的角色,一个人可以担任多个角色。也许总统只获得了一个角色,但这只是偶然选择了错误的例子。
法拉利也不应该继承汽车。以法拉利为例,这一点并不明显,因为他们只生产一种类型的汽车,但考虑到公司生产多种类型的汽车,如货车、轿车、掀背车、卡车等。您可能希望为从汽车类继承的每种类型创建类。然后……您要创建五个从每种类型继承的丰田类吗?比如……
那就太可笑了。
免责声明:我对汽车一无所知。但是...
不要使用继承来建模您的域。曾经。
尝试不使用继承,如何保留您的域也会变得显而易见。
You shouldn't use inheritance to model your domain because you will soon run into trouble once model starts to get complex.
President is simply a role of the person and person can have multiple roles. Maybe president got just one role but that's simply accidental by choosing wrong example.
Ferrari shouldn't be inherited from car either. It's not obvious on Ferrari example, because they only do one type of cars but consider company making many types like vans, sedans, hatchbacks, trucks and so on. You will probably want to make classes for every type that will inherit from car class. And then what... are you going to make five Toyota classes that will inherit from each type? Such as...
That would be ridiculous.
Disclaimer: I know nothing about about cars. However...
Don't use inheritance to model your domain. Ever.
Try it without inheritance and it will also became obvious how to persist your domain.
我认为通过创建这些实体的具体类型,您会开始失去系统的很多灵活性。您所暗示的关系类型是我通常使用“类型”实体处理的东西。例如,你有一辆车。法拉利是一种汽车。由此产生的两个实体是 Car 和 CarType。
按照您所说的方式,每次引入新类型时都必须添加新实体。如果您试图捕获的只是汽车的“昵称”,我认为这只是另一条数据,而不是另一个实体。除非您在不同类型的 Car 实体中具有不同的数据(即不同的属性名称)和/或行为差异,否则您不会通过这种方法获得太多收益。我宁愿使用像 FindCarByType() 这样的存储库方法并处理一种类型的实体,以降低风险。
我绝不是 DDD 专家,我正在为某些概念而苦苦挣扎(或者更像是为某些概念的多种解释而苦苦挣扎)。我发现不存在 100% 纯粹的实现,并且我所看到的每个实现都存在细微差别。
编辑如下
我发现我误读了您所写的部分内容。我发现这个昵称并不适用于所有车辆,而仅适用于法拉利:汽车。我认为答案确实是“视情况而定”。您的模型的其余部分有多少领域专业化?昵称在法拉利实体中可能很普遍,但它是排他性的吗?这不仅与实际数据有关,而且与要求有关。基本上,这取决于您对这些实体的期望程度。
I think you start losing a lot of the flexibility of the system by creating concrete types of these entities. The type of relationship that you are implying is something I generally hand with a "Type" entity. For example, you have a car. A Ferrari is a type of car. The two entities that are borne from that are a Car and a CarType.
The way that you are talking about doing it, you would have to add new entities every time a new type is introduced. If all that you are trying to capture is the "nickname" of the car, I would think that is just another piece of data, and not another entity. Unless you have different data (i.e. different property names) and/or behavior differences in Car entities for different types, you do not gain much with this approach. I would rather have repository methods like FindCarByType() and deal with one type of entity, to reduce risk.
I am by no means a DDD expert, and I am struggling with some concepts (or more like struggling with the multiple interpretations of some concepts). I am finding that there is not a 100% pure implementation, and that there are nuances to each implementation that I have seen.
Edit Follows
I see that I misread part of what you had written. I see that nickname is not for all vehicles, but just for Ferrari : Car. I think that the answer is really "it depends". How much domain specialization do you have in the rest of your model? Having a nickname might be prevalent amongst Ferrari entities, but is it exclusive? It isn't only about the actual data, but the requirements. Basically it comes down to how much specialization your are expecting in these entities.