另一个应用程序架构问题

3

我正在尝试一些DDD,我将尝试以最简单的方式描述我所做的事情。

核心项目
核心项目包含实体、值对象和领域服务。例如,我有一个用户(User)实体和一个用户关系(UserRelation)实体。我想我们都知道什么是用户(User)实体。用户关系(UserRelation)包含有关用户如何相互连接(如关注和双向关注)的信息。因此,我有一个用户领域服务(UserDomainService),其中包含无状态方法,如Follow(user,user)和Connect(user,user)。

public class User
{
    public string Name { get; set; }
    public string Username { get; set; }

    public void ChangeUsername(stirng newUsername)
    {
        ApplyEvent(new UserUsernameChanged(newUsername));
    }
}

public class UserRelation
{
    ctor(User1, User2, isBidirectional)
    public User User1 { get; set; }
    public User User2 { get; set; }
    public bool IsBidirectional { get; set; }
}

public class UserDomainService
{
    public UserRelation Follow(User user1, User user2)
    { 
        return new UserRelation(user1,user2,false);
    }
}

代码库项目

我使用NHibernate,所以我决定不创建这样的项目。相反,我直接使用NHibernate。例如,在我的用户界面中,我从数据库中获取一个用户对象,对其进行更改,然后调用session.Save(user)。

问题

如果我想执行以下操作,我会这样做:

  • 从数据库获取一些信息
  • 从服务中调用Follow(user1, user2)
  • 将UserRelation对象保存到数据库中 最终应用程序代码变得有点复杂。想象一下,如果我们要在2-3个地方使用此代码,并且在某些时候我们必须对其进行重构。

我的解决方案
我的解决方案是创建一个ApplicationService项目,它将完成繁琐的工作并强制消费者使用ApplicationService而不是直接使用实体和域服务。

public class UserApplicationService
{
    ctor(UserDomainService userDomainService){}

    User GetUser(Guid id)
    {
        return NhibernateSession.Get(id)
    }

    public void Follow(Guid user1Id, Guid user2Id)
    {
        var u1 = GetUser(user1Id);
        var u2 = GetUser(user2Id);
        var userRelation = _userDomainService.Follow(u1,u2);
        NhibernateSession.Save(userRelation);
    }

    public void ChangeUsername(Guid user, string newUsername)
    {
        user.ChangeUsername(newUsername);
        NhibernateSession.Save(user);
    }
}

这个应用服务好还是不好?正如您所看到的,新服务也可以充当存储库,因此我们可以创建一个UserRepository类,但现在先跳过这个。让我困扰的是两种方法中的参数。它们接受Guids,并且服务从数据库检索用户。另一种选择是直接传递User对象。ChangeUsername方法与User实体+持久性中的方法类似。

那么,您对此有什么看法?

2个回答

1

个人而言,我并没有看到什么问题,事实上这正是我所在公司的做法。只要你将数据访问从该服务中抽象出来,它就可以作为业务层的中介者连接数据层和 UI 层。这有助于避免重复性工作,并确保对某个操作列出的任何规则都能够被触发。


你能否发送一封电子邮件到mynkow@gmail.com,以便我向您询问一些简单的问题,十分感谢。 - mynkow

1

我的两分钱。

DDD适用于大型项目并且有意义。你不应该仅仅因为它很酷就将其应用于项目中。通过查看NHibernateSession,我发现你可以通过id获取用户。那么如果NHibernateSession负责此操作,你还有哪些其他领域对象?你没有存储库,为什么要强制使用DDD?

好的,假设你有一个大型领域,我不明白为什么要创建一个新项目来托管“关注”功能(在这里输入GUID没有任何问题)。在我看来,“应用程序服务”层不应该处理实体和基础设施,因为这似乎对这个人来说太低层了。应用程序服务层负责整个应用程序,而不是某些领域对象的功能。我注意到你有一个“_userDomainService”,在你的情况下似乎更相关。如果将“关注”功能移动到那里没有太多意义,我会在领域服务层创建另一个服务,称之为“UsersManagerService”或“UsersDomainService”之类的名称。

最后,如果你要实现存储库模式,请考虑通用存储库。


10倍。我会尝试跟进并回答。我的项目很大 :)。上面的代码是伪代码,不是可工作的代码,NHibernateSession实际上是ISession。我创建了一个新项目,因为我有一个“问题”部分。我不同意您关于应用程序服务的观点。我也没有移动跟随功能。核心项目不知道持久性方面的任何信息,这就是为什么我们必须直接使用NHibernate或创建存储库或创建应用程序服务来包装这样的东西的原因。 - mynkow
@mynkow,我没有意识到你有一个大项目。我的意思是,应用层(根据分类而定)通常位于领域层基础设施层之上。对我来说,你描述的功能属于领域层(领域服务),它将根据需要使用基础设施层(ORM)。 - oleksii
好的,我有一个问题。如果我们跳过应用程序层,客户端如何使用Follow操作/命令的代码? authorizationService.IsAllowed("operation/follow", currentUser) -> u1 = repo.Get(user1)->u2 = repo.Get(user2)->var relation = userService.Follow(u1, u2)-> repo.Save(relation). 这对客户端来说太复杂了。这就是为什么我正在尝试将所有这些事情包装在一个applicationService中,它将完成上述所有工作... - mynkow
@mynkow 是的,你说得很对,对于客户端来说应该非常简单 - 最好只需要一两个方法调用,这可以通过服务封装来实现。现在你需要决定将该服务放在哪里。 - oleksii
没错。想象一下还有2-3个其他系统想要使用Follow操作 ;). 感谢交流 :) - mynkow

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接