这是一个有效的对象设计吗? 我有一个域对象,我注入一个服务并调用验证方法来更新对象的状态,如果一切顺利,发送一条确认消息。代码如下:
class Foo {
String bar
Service emailService
public boolean verify() {
bar = "foo"
if(this.save()) {
emailService.sendConfirmation()
}
}
}
Foo.get(1).verify()
在这样的情况下调用emailService是否可以接受?是否有一种设计模式,我可以遵循这种情况使用。
谢谢 - 肯
答案 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
是一个界面,并且您可以注入模拟测试和真实的生产,那么它看起来不错。虽然我认为域对象最好拥有关于自己的知识和逻辑,而不是另一层中的系统(服务)。