是否应将每个对象建模为DDD中的聚合,实体或值对象?

时间:2016-02-02 13:42:35

标签: domain-driven-design aggregateroot domain-events

我在社交网站的设计中使用DDD(包括域名活动)和CQRS(没有事件采购)。

我有像UserFriendRequestFriendship这样的汇总根。我还有UserAddressChangedFriendRequestAccepted等域名活动。其中一些事件需要通知相关用户。所以我想有一个Notification类,比如:

public enum NotificationReason
{
    IncomingFriendRequest = 1,

    OutgoingFriendRequestAccepted = 2,

    // and many more ...
}

public class Notification
{
    public long Id { get; set; }
    public int UserId { get; set; }
    public string UserName { get; set; }
    public string AvatarUrl { get; set; }
    public DateTime Timestamp { get; set; }
    public NotificationReason Reason { get; set; }
    public bool Read { get; set; } //if user has read this notification.
}

但是我应该将Notification类建模为聚合根吗?如果是,当User聚合更改地址并引发UserAddressChanged域事件时,在相应的事件处理程序中,将创建新的聚合Notification,然后通过{{1 }}。 但是在事件处理程序中创建新的聚合对我来说听起来很可疑

与此同时,我也觉得它对于像NotificationRepository这样的简单类来说太重了。我无法确定通知是否属于域名关注或基础设施问题。

2 个答案:

答案 0 :(得分:1)

根据您的描述,它听起来像是'通知'是域事件发射(和订阅)的实现,这表明虽然每种通知都可能值得域对象(值对象,因为它们是不可变的),域事件的传输和接收更多可能是基础设施问题,而不是聚合+存储库

答案 1 :(得分:1)

域中的每个对象都应该是实体或值对象。域中的每个对象都应存在于单个聚合边界内。

并非您应用中的每个对象都是您域中的对象。

  

与此同时,我也觉得它对于像Notification这样的简单类来说太重了。我无法确定通知是否属于域名关注或基础设施问题。

我倾向于同意; CRUD接口(你真的支持修改所有这些属性吗?甚至id?),缺少方法,缺乏业务不变量。你说这些是由事件处理程序创建的 - 这是否意味着大多数这些字段只是原始事件的副本?

通知看起来更像是应用程序问题,而不是域关注问题。在领域专家和无处不在的语言上更加努力,以探索通知是否真的是域的一部分。

  

但是在事件处理程序中创建新的聚合对我来说听起来很可疑。

呃...是的,但也没有。你不会期望一个事件处理程序来创建一个新的聚合,没有。但事件处理程序会安排命令来创建聚合是完全合理的。

此技术通常用于长时间运行的流程(搜索关键字:流程管理器,传奇)。事件处理程序观察消息,并将它们传递给进程,该进程更新自己的状态并在聚合上运行命令,并对其进行舍入和舍入。