我使用工厂按命令对象创建实体,但是当我想从命令对象更新实体时,我找不到一个好的模式来执行此操作。我应该只使用工厂来更新实体,或者如果没有,那么什么是好的模式?
interface ProductFactory {
Product create(ProductCommand command);
Product update(Product product, ProductCommand command);
}
我的服务:
class ProductServiceImpl {
public Product updateProduct(long productId, ProductCommand command) {
Product product = productRepository.findOne(productId);
product = productFactory.update(product, productCommand);
return productRepository.save(product);
}
}
答案 0 :(得分:4)
在DDD上,其中一个战略模式是在代码中使用无处不在的语言。因此,在您的具体情况下,类方法应根据它们的作用命名,如Product::changeTitle
或Priduct::changePrice
:
此外,还有多种建筑风格。其中一个没有命令对象,但有多个参数,如下所示:
class ProductService {
public void changeProductPrice(long productId, double newPrice) {
Product product = productRepository.findOne(productId);
product.changePrice(product, newPrice);
productRepository.save(product);
}
}
这种风格跟随着无处不在的语言。
另一种风格是命令对象参数:
class ProductCommandHandler {
public void handleChangeProductPrice(ChangeProductPrice command) {
Product product = productRepository.findOne(command.getAggregateId ());
product.handleChangeProductPrice(command);
productRepository.save(product);
}
}
第二种风格非常适合CQRS +事件源,您可以通过提取从存储库中识别并加载聚合的通用Application layer
来消除command handler
,它会向命令发送命令,它收集事件,然后将它们保存到Event store
。我经常使用这种风格。
答案 1 :(得分:3)
命名单独回答您的问题。 工厂负责创建事物。是的,在现实世界中,有时工厂收回他们创建的东西以更新它们(想想这里的德国汽车制造商)。
但是在软件的情况下,将工厂变成“维护站”似乎是不好的做法。例如,它与单一责任原则相冲突。除此之外 - 更新对象的工厂非常罕见 - 因此源代码的人类读者会感到惊讶。并且您希望避免令人惊讶的人们阅读您的代码。
我的建议:与我已经提到的“服务”主题保持一致:例如,引入 UpdateService 类是否合理?当然,如果有用于更新和创建的通用代码,那么这应该再次被考虑到公共类中。
答案 2 :(得分:1)
在Domain Driven Design中,应用程序通常直接与聚合根进行交互。
public Product updateProduct(long productId, ProductCommand command) {
Product product = productRepository.findOne(productId);
product.update(productCommand);
return productRepository.save(product);
}
答案 3 :(得分:1)
工厂用于创建对象,而不是用于更新它们。
更新实体是一个持久性方面,由存储库完成。
您必须在应用程序层中执行以下操作:
1)调用存储库以通过id检索要更新的实体。
2)使用从命令获得的值修改所需的实体属性。这是通过调用更新属性的实体方法来完成的。你不应该在工厂里这样做。工厂只是用于创建实体。修改实体是实体提供的行为(方法)。
3)调用存储库以保留实体。