将服务交给实体是否正确?

时间:2012-11-16 03:04:30

标签: domain-driven-design

我知道在实体中(通过构造函数或setter)注入服务通常被认为是一种不好的做法,并让实体保留对它的引用。

但是在调用方法时可以暂时将服务交给实体吗?

例如,假设我要对实体的name字段进行版本设置,并且每次调用VersionServicesetName()创建一个新版本,我可以这样做:

public class Entity
{
    public void setName(String name, VersionService service)
    {
        this.name = name;
        service.addVersion(this, name);
    }
}

我在此代码中喜欢的是,如果不提供setName()就无法调用VersionService方法,从而强制执行所需的行为。通过模拟VersionService,它也很容易测试。

我在double dispatch pattern Jimmy Bogard的帖子中找到了这种方法的示例。

但是从Stack的一些讨论中,我认为普遍的共识是避免在域模型中对服务有任何依赖。

关于这个问题的任何想法?

3 个答案:

答案 0 :(得分:2)

  

但是从Stack的一些讨论来看,我认为一般   达成共识是为了避免对域中的服务产生任何依赖   模型。

服务而言,我很想知道反对在实体中使用它们的论点。域服务是普遍存在的语言中包含的第一类域对象。有很多场景可以证明位于实体中的逻辑可以调用位于域服务中的逻辑,就像调用另一个实体一样。

this article中的Paragaph 3就是一个很好的例子。

答案 1 :(得分:1)

您通常使用域事件生成新版本:

public class Entity
{
    public void setName(String name)
    {
        this.name = name;
        DomainEvent.Publish(new MyEntityGotRenamed(Id));
    }
}

public class YourService : ISubscribeOn<MyEntityGotRenamed>
{
     public void Handle(MyEntityGotRenamed domainEvent)
     {
         var entity = repos.Get(domainEvent.Id);
         AddVersion(entity);
     }
}

您对事件的订阅方式是特定于平台的。

请注意setName不代表域操作。应该是Rename或您客户定义的其他内容。

答案 2 :(得分:1)

域事件方法很好,但它依赖于使用消息驱动架构。

无论如何,特别是对于您给出的示例,我不会将服务作为参数传递,因为IMO并不是使用该服务更新其他模型的实体问题。实体(可能是聚合根)仅关注其自己的模型。调用实体的代码也可以调用服务。

但是,我认为可以将服务作为参数传递,以便检索一些其他必要的数据(遗憾的是我现在想不到一个例子)。但是大多数情况下,您将服务作为构造函数依赖项传递,除了操作之外,您需要该服务并且不能将数据作为方法参数提供。