我正在学习 DDD 并尝试使用 Google Datastore 实现存储库。
我发现从数据存储区重新创建 DDD 实体非常棘手。我已经阅读了将我的 DDD 实体映射到数据存储实体的框架,但我想先学习低级 API。
我虽然,存储库可以使用设置器设置实体的状态,但这通常被认为是 DDD 中的反模式。
另一种方法是使用构建器模式,其中构建器实例被传递给实体的构造函数。然而,这向实体引入了一个超出其职责的功能(恢复实体状态)。
解决问题的好模式是什么?
我正在学习 DDD 并尝试使用 Google Datastore 实现存储库。
我发现从数据存储区重新创建 DDD 实体非常棘手。我已经阅读了将我的 DDD 实体映射到数据存储实体的框架,但我想先学习低级 API。
我虽然,存储库可以使用设置器设置实体的状态,但这通常被认为是 DDD 中的反模式。
另一种方法是使用构建器模式,其中构建器实例被传递给实体的构造函数。然而,这向实体引入了一个超出其职责的功能(恢复实体状态)。
解决问题的好模式是什么?
(答案主要来自我在 OP 中的评论,但我认为最好在答案中详细说明)
二传手很好。问题是域实体的“用户”不应该通过那些 getter/setter 访问。领域实体应该有一个业务有意义的接口,以便应用程序逻辑建立在此基础上。设置器应该是实现级别的东西,用于创建实现对象(在存储库等中)
我认为最好用一个例子来说明。
对于认为是反模式的设置器来说,这是不正确的方式
class OrderApplicationService {
public void cancelOrder(String orderId) {
Order order = orderRepository.getOrder(orderId);
order.setOrderStatus(CANCELLED);
order.setOpenQuantity(0);
orderRepository.update(order);
}
}
但是更正确的方法是:
// Interface for Order
interface Order {
void cancel();
// no setters!!!
}
class OrderImpl extends Order {
@Override
void cancel() {
this.status = CANCELLED;
this.openQuantity = 0;
}
void setId(String orderId) { ... }
// some other setters
}
class OrderApplicationService {
public void cancelOrder(String orderId) {
Order order = orderRepository.getOrder(orderId);
order.cancel();
orderRepository.update(order);
}
}
Repository 通过 impl 创建和访问,因此它可以访问 getter/setter。但是,您的应用程序逻辑仅面向接口,并且您没有使用 setter/getter 实现逻辑(这是反模式)
上述方式是通过正确的接口声明来执行的。然而,如果你认为你可以依靠自我声誉,你可以通过在 Impl 中直接拥有与业务逻辑相关的方法和 setter/getter 来简化故事,省略接口。在你的实现过程中,你应该知道在你的业务逻辑实现过程中你应该只使用实体的业务方法(而不是 getter/setter)。
而且,将 setter 视为反 DDD 并不是一个简单的经验法则。在某些情况下,例如,将自由文本评论存储在实体中,提供 setter 作为业务逻辑方法不一定是错误的决定。
Eric Evans书的整个第 6 章都专门针对您所描述的问题。
首先,DDD 中的 Factory 不必是独立的服务 -
埃文斯 DDD,p。139:
有很多方法可以设计 FACTORIES。Gamma et 中彻底处理了几种特殊用途的创建模式——FACTORY METHOD、ABSTRACT FACTORY 和 BUILDER。al 1995. <...> 这里的重点不是深入研究工厂设计,而是展示工厂作为领域设计的重要组成部分的位置。
Evans FACTORY 中的每个创建方法都强制执行创建对象的所有不变量,但是,对象重构是一种特殊情况
埃文斯 DDD,p。145:
重构对象的 FACTORY 将以不同的方式处理对不变量的违反。在创建新对象期间,当不满足不变量时,FACTORY 应该简单地阻止,但在重构时可能需要更灵活的响应。
这很重要,因为它引导我们为创建和重构创建单独的 FACTORIES。(在第 155 页的图表中TradeRepository使用专门的SQL TradeOrderFactory,而不是通用的TradeOrderFactory)
所以你需要为重构实现一个单独的逻辑,并且有几种方法可以做到这一点(你可以在 Martin J Fowler Patterns Of Enterprise Application Architecture中找到完整的理论,第 169 页有一个子标题Mapping Data to Domain Fields,但不是所描述的所有方法看起来都很合适(例如,在 java 中使对象字段包私有似乎太侵入性)所以我只喜欢以下两个选项之一
关于带有 setter/getter 的贫乏领域模型,即将出版的 Vaughn Vernon 书对这种方法提出了很多批评,所以我敢说它是DDD 中的一种反模式。