我正在使用的域名是会员制。我有一个名为“注册邀请期”的域名概念,在此期间用户可以邀请其他人注册会员资格。注册邀请期可以打开/关闭并持有邀请。邀请函是姓名和电子邮件地址。
我有一个要求:当注册邀请期开放时,它应该联系任何未提出的邀请。在我看来,这是入学邀请期课程应该负责的事情。它可以访问满足此业务需求所需的所有信息。
接下来,我有一个电子邮件服务。它负责获取模板,构建和发送电子邮件。它是基础设施。
所以我的问题。注册邀请期域名对象应如何与电子邮件服务进行交互。
A)将服务(通过抽象)注入联系功能?这是否将域与基础设施紧密联系在一起?
var period = repo.Get(id);
period.ContactInvitations(emailService);
B)编写一个查询邀请期的域名服务以获取信息?
(In Service)
var period = repo.Get(id);
if (period.IsOpen)
{
var unconcacted = period.GetUncontactedInvitations();
foreach(var i in uncontacted)
{
var email = BuildEmailFromInvitaion(i);
emailService.Send(email);
}
}
从我的直觉来看,A似乎更好。 B似乎没有反映“邀请期间联系被邀请者”的语言。
答案 0 :(得分:1)
A)将服务(通过抽象)注入联系功能?这是否将域与基础设施紧密联系在一起?
这一点,理解为您传入的抽象是域服务。
var period = repo.Get(id);
period.ContactInvitations(emailService);
这里的拼写非常好,只要emailService
是域名服务;它公开的电子邮件功能应该用域模型的语言表示。
在此模式中,域服务充当接受域概念作为参数的适配器,并将它们传递给电子邮件基础结构。
这是否会将域与基础架构紧密联系在一起?
不,因为域服务充当模型和基础架构之间的接缝 - 您可以轻松地将与电子邮件基础架构通信的域服务实例替换为与测试双重对话的实例。
从我的直觉来看,A似乎更好。 B似乎没有反映“邀请期间联系被邀请者”的语言。
B违反了Tell, Don't Ask。这不一定是错的(工程是权衡)但其他条件相同,这不是我的首选。
该服务将负责将邀请转换为电子邮件并将该邮件发送到基础设施电子邮件服务。它还会将邀请标记为已发送。是吗?
也许 - 聚合仍然负责跟踪自己的状态;域服务只是处理电子邮件部分;这个域名服务真的不应该对你的模型的内部有任何了解。
Period::ContactInvitations(emailService) {
for(invitation : uncontacted) {
if (emailService.contact(...)) {
this.onContacted(invitation);
}
}
}
伪代码给你基本的想法 - 你会想要考虑失败模式等等。