非常好的问题。我花了很多时间思考这样的主题。
您通过注意到表达领域模型和关注点分离之间的紧张关系表现出了极大的洞察力。这很像我所问的
告诉不要询问和单一职责原则的问题中的紧张关系。
以下是我的观点。
领域模型是贫血的,因为它不包含任何领域逻辑。其他对象使用贫血领域对象获取和设置数据。您描述的内容对我来说听起来不像是领域逻辑。它可能是,但通常而言,查找表和其他技术语言最有可能是我们理解的术语,但不一定对客户有什么意义。如果我理解有误,请澄清一下。
无论如何,领域对象的构建和持久化都不应该包含在领域对象本身中,因为那不是领域逻辑。
因此,回答这个问题,不,您不应该注入大量非领域对象/概念,比如查找表和其他基础设施细节。这是一个关注点泄漏到另一个关注点中。领域驱动设计中的工厂和存储库模式最适合将这些关注点与领域模型分开。
但请注意,如果您没有任何领域逻辑,那么您最终会得到贫血的领域对象,即一堆无脑的getter和setter,这就是
一些商店声称进行SOA/服务层的方式。
所以,如何兼顾两者的优点呢?如何将你的领域对象专注于领域逻辑,同时将UI、构造、持久化等因素排除在外?我建议您使用像
双重分派这样的技术,或者某种形式的
限制方法访问。
以下是双重分派的示例。假设您有以下代码行:
entity.saveIn(repository);
在您的问题中,saveIn() 将拥有关于数据层的各种知识。使用双重分派,saveIn() 实现了以下功能:
repository.saveEntity(this.foo, this.bar, this.baz);
而仓库的saveEntity()方法拥有保存数据层信息的全部知识,这正是应该的。
除了这种设置,你还可以拥有:
repository.save(entity);
这只是调用
entity.saveIn(this)
我重新阅读了这篇文章,发现实体仍然很薄,因为它只是将其持久性分派给存储库。但在这种情况下,实体应该很薄,因为您没有描述任何其他领域逻辑。在这种情况下,您可以说“放弃双重调度,给我访问器”。
是的,您可以这样做,但在我看来,它会暴露出您的实体实现方式太多,而且那些访问器会分散领域逻辑的注意力。我认为唯一应该有gets和sets的类是以“Accessor”结尾的类。
我很快就会结束这个话题了。就我个人而言,我不会使用saveIn()方法编写我的实体,因为我认为即使只有一个saveIn()方法,也会使领域对象杂乱无章。我使用友元类模式、包私有访问或可能是
Builder模式。
好了,我说完了。正如我所说,我已经对这个主题着迷了相当长时间。