如何在DDD聚合中处理getOrCreateIfAbsent?

时间:2015-10-22 14:09:53

标签: java domain-driven-design

我有我的要求的情况我希望看到有人对此有强烈的意见。

我正在进行的项目要求,在客户将产品添加到购物车时,如果购物车不存在,则必须创建购物车。目前,聚合是客户,它包含包含产品的购物车。由于该系统是支持真实电子商务项目的一方,因此一旦收到“AddProductCommand”,就会认定客户和购物车的创建是理所当然的。在这种情况下,如果客户和购物车不在那里,则必须创建它们。

我的当前实现在应用程序服务中创建了Customer(如果它不存在)。创建后,我使用AddProductRequest传递customer.addProduct(addProductRequest)AddProductRequest包含购物车ID和产品ID。这个问题来了。一旦进入客户聚合,如果购物车不存在,我必须创建它。所以基本上,我在客户中没有addCart,我首先调用Cart实体然后调用addProduct。我需要创建购物车,如果它不在Customer聚合内部,然后将产品添加到它。要做到这一点,我不创建任何工厂,因为我不希望有一个使测试复杂化的静态方法,我也不能在聚合中创建一个新的工厂。我只是在受保护的方法中使用new运算符创建Cart实体,在测试时我会覆盖它以验证我在那里做什么。

所以我的问题是,这是一种有效的方法吗?在我的脑海中,要将产品添加到购物车,应首先将购物车添加到客户,如果不存在则将其失败。要做到这一点,我需要向应用程序服务添加逻辑,首先我会询问客户是否有带有该ID的购物车,否则创建它,并在添加产品之前将其添加到客户。我可以添加一个提供此请求的域服务但是我需要注入工厂来创建Cart,当我在几个地方读取域服务不应该注入任何工厂时,应该是应用服务的工作。

我可以这样做,但项目将来会变得更加复杂,因为还有另一层可以添加一个产品列表,如果它们不存在,还必须创建客户,购物车和产品消耗AddVoucherCommand时。在这种情况下,如果我不想在模型中创建实体,我需要在应用程序/域服务中检查每个聚合或实体是否在其中具有必要的实体,我认为这不是非常DDD友好,或者只是继续做我现在正在做的事情。也就是说,每个聚合/实体在调用addXXXX方法之前负责创建必要的实体。

一些简化的代码来解释我现在正在做的事情以及将来我将要做的事情:

public class CustomerService {
    public void addVoucher(AddVoucherRequest addVoucherRequest) {
        Customer customer = customerRepo.load(customerId);
        customer.addVoucher(addVoucherRequest);
        customerRepo.save(customer);
    }
}

public class Customer() {
    public void addVoucher(AddVoucherRequest addVoucherRequest) {
        Cart cart = getOrCreateIfAbsent(addVoucherRequest.getCartId());
        cart.addVoucher(addProductRequest);
    }
    private Cart getOrCreateIfAbsent(long cartId){
        Optional<Cart> cart = carts.stream().filter(cart -> cart.getId() == cartId).findFirst();
        return cart.orElseGet(() -> {
             Cart newCart = createCart(cartId);
             carts.add(newCart);
             return newCart;
        }
     }
     protected Cart createCart(long cartId) {
         return new Cart(cartId);
     }
}
public class Cart() {
     public void addVoucher(AddVoucherRequest addVoucherRequest) {
         Product product = getOrCreateIfAbsent(addVoucherRequest.getProductId());
         product.addVoucher(addVoucherRequest);
     }
     private void getOrCreateIfAbsent(long productId) {
         Optional<Product> product = products.stream().filter(product -> product.getId() == productId).findFirst();
        return product.orElseGet(() -> {
             Product newProduct = createProduct(productId);
             products.add(newProduct );
             return newProduct ;
        }
     }
     protected Product createProduct(long productId) {
         return new Product(productId);
     }
 }

有什么建议吗?

谢谢!

1 个答案:

答案 0 :(得分:2)

选择等待客户订购某些内容以在新系统中创建他/她,而不是从旧系统中预先导入所有客户,这纯粹是技术决策,它与您的域IMO无关。

因此,它不应该以任何方式影响您设计域对象的方式 - 据我所知,getOrCreateIfAbsent()应该是某种应用程序服务中的行为,而不是您的某个实体中的行为。 / p>