【问题标题】:DDD - Contacting an invitationDDD - 联系邀请
【发布时间】:2018-04-16 16:42:47
【问题描述】:

我正在使用的域是会员系统。我有一个域概念,叫做 Enrollment Invitation Period,在此期间用户可以邀请其他人注册成为会员。注册邀请期可以打开/关闭并保留邀请。邀请是姓名和电子邮件地址。

我有一个要求:当注册邀请期开放时,它应该联系任何未联系的邀请。在我看来,这是 Enrollment Invitation Period 班级应该负责的事情。它可以访问满足此业务需求所需的所有信息。

接下来,我有一个电子邮件服务。它负责获取模板、构建和发送电子邮件。它是基础设施。

所以我的问题。 Enrollment Invitation Period 域对象应如何与电子邮件服务交互。

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 似乎没有反映“邀请期间联系受邀者”的语言。

【问题讨论】:

    标签: domain-driven-design


    【解决方案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);
            }
        }
    }
    

    为您提供基本概念的伪代码 - 您需要考虑故障模式等。

    【讨论】:

    • 好的。让我看看我是否理解这一点。我可以创建一个名为 InvitationSender 的域服务,它会接受域对象邀请。该服务将负责将邀请转换为电子邮件并将该消息发送到基础设施电子邮件服务。它还会将邀请标记为已发送。对吗?
    猜你喜欢
    • 2016-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-01
    相关资源
    最近更新 更多