假设我的域中有2个聚合根(AR),并且在1上调用某个方法需要访问第2个实例。 在DDD中,如何以及在何处检索和创建第二个AR?
这是一个需要访问TravelerEntity
的人为举例SuitcaseEntity
。我正在寻找一个不会使用基础设施代码污染域层的答案。
public class TravelerEntity {
// null if traveler has no suitcase yet.
private String suitcaseId = ...;
...
// Returns an empty suitcase ready for packing. Caller
public SuitcaseEntity startTrip(SuitcaseRepository repo) {
SuitcaseEntity suitcase;
if (suitcaseId == null) {
suitcase = new SuitcaseFactory().create();
suitcase = repo.save(suitcase);
suitcaseId = suitcase.getId();
} else {
suitcase = repo.findOne(suitcaseId);
}
suitcase.emptyContents();
return suitcase;
}
}
处理启动行程请求的应用程序层服务将通过DI获得适当的SuitcaseRepository
实现,通过TravelerEntity
实现获取TravelerRepository
并调用其startTrip()
方法。
我想到的唯一选择是将SuitcaseEntity
管理转移到域名服务,但我不想在开始旅行之前创建行李箱,我不想最终导致贫血TravelerEntity
。
我对一个AR创建并保存另一个AR有点不确定。这是好的,因为回购和工厂封装了关于第二个AR的细节?我不知道有危险吗?还有更好的选择吗?
我对DDD有足够的新意,可以质疑我对此的看法。我发现的关于AR的其他问题似乎都集中在正确识别它们,而不是关于彼此管理它们的生命周期。
答案 0 :(得分:4)
理想情况下,TravelerEntity
不会操纵SuitcaseRepository
,因为它不应该知道存储手提箱的外部事物,只知道它自己的内部结构。相反,它可以新建SuitCase
并将其添加到其内部[行李箱列表]。如果您希望在没有专门将行李箱添加到存储库的情况下使用ORM,那么您必须将整个行李箱对象存储在TravelerEntity.suitcaseList
而不仅仅是其ID,这与"将对其他AR的引用存储为ID"最佳实践。
此外,TravelerEntity.startTrip()
返回行李箱看起来有点人为且不明显,如果您需要返回由startTrip()
创建的其他实体,您将遇到麻烦。因此,一旦将行李箱数据添加到其列表中,一个好的解决方案就是让TravelerEntity
发出一个带有行李箱数据的SuitcaseAdded
事件。应用程序服务可以订阅该事件,将行李箱添加到SuitcaseRepository
并提交交易,从而有效地将新行李箱和修改过的旅行者保存到数据库中。
或者,您可以将startTrip()
放在域服务中而不是实体中。使用SuitcaseRepository
可能更合法,因为允许域服务了解多个域实体以及整个域进程。
答案 1 :(得分:0)
首先,持久性不是域的工作,所以我会从域模型中删除所有存储库并创建一个可以使用它们的服务。
其次,你应该重新考虑你的设计。为什么Traveler的StartTrip方法应该返回SuitCase?
旅行者要么拥有或没有行李箱。一旦您检索到旅行者,您就应该已经拥有了他们的SuitCases。
public class StartTripService {
public void StartTrip(int travellerId) {
var traveller = travellerRepo.Get(travellerId);
traveller.StartTrip();
}
}