【发布时间】:2012-06-12 05:06:14
【问题描述】:
如果您要在 DDD 应用之上为 CRUD 设置一个 REST 层,您是否会让 REST 层吐出域模型(就数据而言)(比如 GET)?
【问题讨论】:
如果您要在 DDD 应用之上为 CRUD 设置一个 REST 层,您是否会让 REST 层吐出域模型(就数据而言)(比如 GET)?
【问题讨论】:
通常,您希望能够更改域对象(例如,当您了解有关域的新知识时),而不必更改系统的公共接口/API。反过来也是一样:如果需要对公共接口进行更改,您就不必更改域模型。
所以从这个角度来看,我永远不会在公共接口上按原样公开我的域对象。相反,我会创建作为公共接口一部分的数据传输对象 (DTO)。这样,对我的域和公共 api 的更改可以独立更改。
【讨论】:
您不应公开 DDD 模型。这是绝对正确的,因为 SOA 前端不应该向客户端公开实现细节。您的用户应该依赖于一个业务功能,而不是一个实现细节……但这假设了一个很好的设计,将几个可能是异构的应用程序联合到一个 SOA 总线中。
我想补充一下答案,因为提到 CRUD 接口让我认为这可能是 SOA 滥用的一个案例,其中 SOA 原则用于粘合应用程序的各个层,而不是应用程序网络。 SOA 是企业沟通其系统的一种方式,而不是一种实现 MVC 的方式!如此简单却又如此被误解。例如,仅仅因为您的前端 GUI 使用服务来访问后端,您就没有“SOA 应用程序”……这意味着什么。
如果这是用于粘合层的 SOA 案例,请修改您的设计并为该抽象级别使用适当的设计架构。否则你会误解这里关于不暴露 DDD 模型和不使用 CRUDY 的建议,你最终肯定会为服务接口创建一个单独的域模型,然后你必须映射到 DDD,这太复杂了你将需要使用推土机之类的东西来映射具有不同名称的同一事物,等等,直到我们最终得到一个臃肿的无法维护的混乱......
.. 小心点。
-亚历克斯
Redzedi 说的太对了,我们需要澄清一下......
就像所有事情一样,做起来比说起来要复杂得多。序列化一个复杂的域模型可能非常困难,以至于您最终要么不将任何逻辑放入域中,贫血模型反模式 (http://martinfowler.com/bliki/AnemicDomainModel.html),要么有一个单独的贫血模型持久性,即 DTO。
我不知道什么是最糟糕的,但两种选择都很糟糕。您应该将模型中的逻辑放入模型中,并且您应该能够在任何地方直接序列化。
根据我多年使用领域模型的经验,我相信最好的事情是中间的一点。是的,正如 Fowler 和 Evans 所说,业务对象应该带有逻辑,但不是所有(http://codebetter.com/gregyoung/2009/07/15/the-anemic-domain-model-pattern/)都有一点贫血好的服务层是最好的。
例如,发票应了解其项目并具有计算其总额的程序,这取决于项目。但是发票的项目不需要知道发票。那么当一个项目的成本发生变化时,它是否应该有一个指向父发票的指针作为循环引用并调用发票的总计算过程?
我相信不会。我认为这是服务层的任务,它应该首先接收事件然后编排过程,而不必为了实现目的将所有业务对象耦合在一起,也不必违反业务交互规则,而这正是领域模型的用途。
-亚历克斯
【讨论】: