在域对象方法中封装服务调用

时间:2010-09-01 23:12:51

标签: design-patterns domain-driven-design

这是一个有效的对象设计吗? 我有一个域对象,我注入一个服务并调用验证方法来更新对象的状态,如果一切顺利,发送一条确认消息。代码如下:

class Foo {
  String bar
  Service emailService


  public boolean verify() {
    bar = "foo"
        if(this.save()) {
            emailService.sendConfirmation()
        }
  }
}

Foo.get(1).verify()

在这样的情况下调用emailService是否可以接受?是否有一种设计模式,我可以遵循这种情况使用。

谢谢 - 肯

3 个答案:

答案 0 :(得分:11)

从实体调用服务没有任何问题。但是,在实例化这些服务方面存在一些问题。如果您遵循此路径,则必须以某种方式在实体创建期间获取服务实例,这是有问题的。

直接调用构造函数显然是一个坏主意(因为它将实体耦合到服务实现)。

Jimmy Bogard解释了为什么injecting services into entities is a bad idea

而不是它,他建议使用'double dispatch'(如果这个名称合适,有一些辩论)模式来解决这个问题。在此方法中,域方法被调用者向域方法提供服务实现。在你的情况下,它看起来像这样:

class Foo {
  String bar    

  public boolean verify(Service emailService) {
    bar = "foo"
        if(this.save()) {
            emailService.sendConfirmation()
        }
  }
}

Foo.get(1).verify(new Service(...))

最后(但并非最不重要)选项是使用域事件模式。您可以在Udi Dahan's blog上阅读相关信息。在此方法中,实体仅负责发布由适当处理程序订阅的有意义事件。您可以阅读所有这些技术的完整比较on my blog

希望有所帮助

答案 1 :(得分:3)

关于这一点的坏处是你失去了你的域模型的隔离。 您的域模型了解电子邮件服务,这是纯粹的基础架构。

引入应用程序服务可能是个好主意。 事件模式也可以解决问题。

答案 2 :(得分:2)

我通常会从地方发送确认信(行动?),从那里调用验证。如果验证的结果是发送许多确认电子邮件,那么我可能会Foo生成并返回ConfirmationMessage s(域对象),它将封装所有知识以进行确认。然后,该操作可以将这些消息排入队列以进行调度。

话虽如此,如果您的Service是一个界面,并且您可以注入模拟测试和真实的生产,那么它看起来不错。虽然我认为域对象最好拥有关于自己的知识和逻辑,而不是另一层中的系统(服务)。