我们的聚集根如下。
@AggregateRoot
class Document {
DocumentId id;
}
客户端给出的问题语句是"文档可以将多个文档作为附件"
因此,重构该模型将导致
//Design One
@AggregateRoot
class Document {
DocumentId id;
//Since Document is an aggregate root it is referenced by its id only
Set<DocumentId> attachments;
attach(Document doc);
detach(Document doc);
}
但是,仅此模型就不够,因为客户希望存储一些有关附件的元信息,例如附件以及附件的何时。这将导致创建另一个类。
class Attachment {
DocumentId mainDocument;
DocumentId attachedDocument;
Date attachedOn;
UserId attachedBy;
//no operation
}
我们可以再次对文档模型进行重构
//Design Two
@AggregateRoot
class Document {
DocumentId id;
Set<Attachment> attachments;
attach(Document doc);
detach(Document doc);
}
我能想到的建模的不同可能性如下。
- 如果我使用设计,那么我可以将
Attachment
类建模为汇总根,并在附加文档时使用事件来创建它们。但这看起来不像是一个骨料。 - 如果我选择两个设计,则可以将
Attachment
类建模为值对象或实体。 - ,或者如果我使用CQR,我可以使用Design One,并使用型号
Attachment
作为查询模型并使用事件填充它。
so,哪种正确的方法是建模这种情况?还有其他方法可以对我提到的其他方法建模?
您可能会从长远来看,传递值而不是实体使您的代码更易于管理。如果附件/分离不关心整个文档,则只需传递他们关心的位(又称界面隔离原理)。
attach(DocumentId);
detach(DocumentId);
仅此模型就不够,因为客户想要存储有关附件的一些元信息,例如谁附加了附件。
是的,这很有意义。
哪种正确的方式?
没有足够的信息(有礼貌地说"取决于"。)
通常通过查看行为而不是结构或关系来发现汇总边界。附件关系是您可以添加/删除的不变值,还是具有随着时间变化的内部状态的实体?如果您更改附件,您还需要哪些其他信息,等等。