域服务注入域实体

Mad*_*Max 3 c# domain-driven-design dependency-injection

我正在学习域驱动设计,并且对实体和向其注入域服务有些困惑。我发现此博客的结论是将服务注入实体是一个坏主意。我部分同意这一点,但是在这种情况下该怎么做:我有一个User实体,它是一个聚合根,其中包含Password值对象。看起来像这样:

密码值对象:

public class Password  
{  
    public string Hash { get; private set; }

    public string Salt { get; private set; }

    private readonly IHashGeneratorService _hashGeneratorService;

    public Password(IHashGeneratorService hashGeneratorService)
    {
        _hashGeneratorService = hashGeneratorService;
    }

    public void GenerateHash(string inputString)
    {
        //Some logic

        Salt = hashGeneratorService.GenerateSalt();
        Hash = hashGeneratorService.GenerateHash(inputString);
    }
}
Run Code Online (Sandbox Code Playgroud)

用户实体:

public class User
{
    public Password Password { get; private set; }

    public User(IHashGeneratorService hashGeneratorService)
    {
        this.Password = new Password(hashGeneratorService);
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,如果我通过工厂创建User实体,则需要向工厂构造函数或Create()方法提供IHashGeneratorService实现。在那之后,如果我的工厂被使用,例如。SomeUserService我必须为其提供实现(例如,通过ctor注入)。依此类推...老实说,它从我身上散发出来,因为我的许多类都依赖于哈希生成器服务实现,但只有密码类使用它。而且我认为这也违反了密码类的SRP原理。

我发现了一些解决方案:

  1. 使用服务定位器。但是它也有气味,因为它是一种反模式,如果我们使用它很难测试和管理实体。

  2. 直接在密码方法中实现哈希算法。

  3. 坚持上面所说的:)缺点,优点是我的类更易于测试,因为我可以提供模拟服务而不是完整实现。

就我个人而言,我倾向于将我的代码重新构造为第二种解决方案,因为它不会破坏SRP(或者会破坏SRP?:)),类不依赖于哈希服务实现。还有吗?还是您还有其他解决方案?

pla*_*alx 5

我对DDD相当陌生,但是我相信散列密码不是域的问题,而是技术上的问题,就像持久性一样。哈希服务应在domain中定义其接口,但应在基础结构层中实现。然后,应用程序服务将使用哈希服务对密码进行哈希处理并创建Password实例(应该是值对象),然后再将其传递给User聚合根。

在某些情况下,例如依赖项解析非常复杂且特定于域时,聚合必须使用服务。在这种情况下,应用程序服务可以将域服务传递到聚合方法中。然后,聚合将向该服务进行两次分派以解析引用。

有关更多信息,您可以阅读Vaughn Vernon编写的《实现域驱动的设计》一书。他在第362页(模型导航)中谈到了这一点,在本书的其他一些地方也谈到了这一点。