3

想象一下,您建立了一个社交网络。有些用户可以将其他用户添加为好友。您如何在 DDD 中对此进行建模?自然,您不能简单地在User班级中拥有朋友列表,因为任何朋友循环都会导致从存储库中获取此类用户时的无限递归。

如果您需要跟踪可能处于待处理、取消、接受或拒绝的好友请求,您将如何更改模型?

4

3 回答 3

4

嗯...其实按照你的要求去做是很容易的,而且你的情况是标准的。您不必在聚合中存储实际对象User,只需将作为.FriendslistUserUser

这是 Vaugh Vernon 提出的聚合实现规则之一:通过 ID 链接到其他聚合和实体。所以没有循环,只有 ID 列表。

在那种情况下,某人成为某人的朋友,您必须一次更改两个聚合。这可能是不受欢迎的行为,因为更改不能在一个事务中立即发生。但是对于这种情况,您有域事件,并且可以轻松地对好友请求进行建模:您的聚合可以通过、 或FriendshipRequested事件FriendshipAccepted相互通信并相应地更改它们的状态。FriendshipCancelledFriendshipDeclined

在这种情况下,您还可以免费收到日志和通知。

于 2013-02-08T08:41:26.230 回答
1

AUser可以有一个Friends 的列表。AFriend可以由 UserId、FriendType、GroupId 等组成。

AUser也可以有一个FriendRequests 的列表。AFriendRequest可以有一个 UserId、RequestMessage、RequestStatus 等。

UserFriend并且FriendRequest都可以是同一个聚合的一部分。但是这样做可能会有一些重复。另一种选择是为所涉及的两个用户创建一个 FriendRequest,每个用户都有一个接收和发送的FriendRequestID 列表。

这只是给您一些想法,因为在 DDD 中,您的设计将高度依赖于您的应用程序将如何工作以及需要哪些功能。;-)

于 2013-02-08T01:28:19.213 回答
1

这在很大程度上取决于您的一致性边界需要在哪里。因此,这也取决于您拥有哪些业务规则。

虽然 Meta-Knight 在同一个 Aggregate 中有 FriendRequest,但我会将它作为它自己的并使用事件在 Aggregates 之间进行通信,因此使 Person 和那里的 FriendRequests 最终保持一致。这将允许你做类似的事情。

public class DomainRouter {
    public void When(FriendRequestCreated event)
    {
            //Send command to each Person to record request
    }

    public void When(FriendRequestAccepted event)
    {
            //Send command to Person to record request accepted and add friend.
            //Send comamnd to Person who accepted to add Friend
    }

    public void When(FriendRequestDeclined event)
    {
            //Send command to update Friend request on person.
            //Send command to Person who declined to record they have declined?
    }
}

因此,关于 Person 的信息只是状态记录。FriendRequest Aggregate 将是所有过程实际发生的地方。

在 DDD 中重要的是考虑行为。FriendRequest 可以被请求、撤回、接受和拒绝。一个人能做什么?一个人是否需要被 DDDd 或者你可以让它变得更好并且简单地 CRUD + 将信息存储到图形数据库等中。

也许您想以一种可以访问 person.requestFriendAcceptance(Person id) 的方式对其进行建模,在这种情况下,路由器可能只会通过通知朋友一个 FriendRequest 来处理 FriendRequestCreated 事件。

于 2013-02-08T01:49:00.493 回答