DDD实施

ras*_*cio 8 domain-driven-design

我是领域驱动设计的新手,我对一些概念有所怀疑(希望这是一个正确的问题).
我知道在DDD我应该避免贫血模型,所以考虑一个社交网络模型应该(保存)两个朋友之间的友谊?
我想象有一个代表用户的类(使用类似Java的语法)的情况:

class User{
    String username
    List<User> friends
}
Run Code Online (Sandbox Code Playgroud)

那么,它应该有一个添加朋友的方法

class User{
    void friendship(User friend)
}
Run Code Online (Sandbox Code Playgroud)

或者我应该使用服务吗?

class UserService{
     void friendship(User user, User user2)
}
Run Code Online (Sandbox Code Playgroud)

aro*_*eer 6

我的想法是,这是关系数据库理论被称为"弱实体"的一个例子.A Friendship只能通过User友谊中涉及的两个标识符来识别,但可以有自己的属性,例如何时创建它以及它是什么类型的关系.

我会把它作为自己的实体,并且可能将它隐藏在由User对象暴露的外观后面:

class User {
    protected List<Friendship> _friendships { get; private set; }

    public IEnumerable<User> Friends {
        get { return _friendships.Select( /* get other user */ ); }
    }

    public void AddFriend(User otherUser) {
        // check to see if friendship exists
        // if not, create friendship
        // do other friendshippy things

        // make sure the other user knows about our friendship 
        // and gets to do its friendshippy things
        otherUser.AddFriend(this);
    }
}
Run Code Online (Sandbox Code Playgroud)


Gia*_*sio 5

我会用类似的东西

public sealed class Username : IEquatable<Username> { /* string wrap here */ }
public class User
{
    private readonly Username _username;
    private readonly HashSet<Username> _friends;
    public User(Username username)
    {
        if (null == username) throw new ArgumentNullException("username");
        _username = username;
        _friends = new HashSet<Username>();
    }

    public Username Name { get {return _username; } }
    public void Befriend(User user)
    {
        if (null == user) throw new ArgumentNullException("user");
        _friends.Add(user.Name);
    }

    public bool IsFriendsOf(User user)
    {
        if (null == user) throw new ArgumentNullException("user");
        return _friends.Contains(user.Name);
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,根据Demeter法则,用户不会公开任何集合.如果你真的需要它们,我会IEnumerable<Username>为朋友揭露.

此外,在DDD中,所有查询和命令都应该是无处不在的语言的一部分(这就是我用来Befriend代替的原因AddFriend).

但是,让我说这看起来有点太CRUD需要DDD.如果您(至少)不需要域专家来理解域,则根本不需要DDD.如果您不需要DDD,它将成为项目中最昂贵的错误.

编辑
让我们假设领域专家声明"友谊永远是互惠的"(根据guillaume31的建议):通过建模幂等命令,您可以非常轻松地确保这样的业务规则.该Befriend命令变为:

public void Befriend(User user)
{
    if (null == user) throw new ArgumentNullException("user");
    if(_friends.Add(user.Name))
    {
        user.Befriend(this);
    }
}
Run Code Online (Sandbox Code Playgroud)

始终可以使用此类属性对幂等命令进行建模,但有时需要进行更多分析以确保其参数及其内部状态提供所需的一切.