存储库引发事件并注入依赖项

时间:2014-04-14 21:16:24

标签: domain-driven-design ddd-repositories

请查看以下存储库。是否可以使用DDD规则,该存储库会注入一些依赖项并引发事件?我读到该存储库通常属于infrastracture,不应该做这样的事情。您如何看待这种方法? 也许最好在域服务​​中包装存储库调用并执行事件源和依赖注入? :

public class JpaOrderRepository implements OrderRepository{

@Inject 
Private RebatePolicyFactory rebatePolicyFactory;
@Inject 
Private InjectorHelper injector;
@Inject 
DomainEventPublisher eventPublisher;

public  void persist(Order order) {
 super.persist(order);
 eventPublisher.publish(new OrderCreatedEvent(order.getEntityId())); // !! **Events**
}

Public  Order load(OderId orderId) {
 Order order = super.load(orderId);
 injector.injectDependencies(order);
 order.setRebatePolicy(rebatePolicyFactory.createRebatePolicy()); // !! **Dependencies**
 return order;
}


}

代码取自https://code.google.com/p/ddd-cqrs-sample/source/browse/branches/ddd_cqrs-sample/jee/src/main/java/pl/com/bottega/erp/sales/infrastructure/repositories/jpa/JpaOrderRepository.java?r=190

1 个答案:

答案 0 :(得分:1)

Repository是一种DDD模式,它声明您希望抽象行为像伪集合,以封装更改数据的操作。您只应在更改数据之前使用存储库加载数据。

类似的东西:

public class AnApplicationService
{
    public void addItemToOrder(orderId, item)
    {
        Order order = repo.load = (orderId);
        order.AddItem(item); // You could publish the event inside AddItem if you prefered
        repo.persist(order);
        eventPublisher.publish(new ItemAddedToOrderEvent(orderId));
    }
}

如果您需要检索订单,因为您想向用户显示有关订单的信息,但您不需要修改订单,则不应使用存储库模式。你需要使用别的东西。

public class AnApplicationService
{
    public ReadOnlyOrder GetOrder(orderId)
    {
        ReadOnlyOrder order = finder.findReadOnlyOrderById(orderId);
        /* You could put those 3 lines inside your finder.findReadOnlyOrderById implementation if you prefer */
        injector.injectDependencies(order);
        order.setRebatePolicy(rebatePolicyFactory.createRebatePolicy());
        return order;
    }
}

否则,我认为你没有使用足够的抽象。在您的Core中,您需要所有存储库,finder和eventPublisher的接口。

public interface IOrderRepository
{
     void persist(Order order);
     Order load(OrderId orderId);
}
public interface IFinder
{
     ReadOnlyOrder findReadOnlyOrderById(OrderId orderId);
}
public interface IEventPublisher
{
     void publish(IEvent event);
}

现在,在您的基础结构中,您可以创建扩展这些接口的具体类。您可以自由地使这些依赖于DI方式,并让他们发布事件。但代码的其他地方应该使用接口,而不是这些具体的实现。同样,你的repo应该注入一个IEventPublisher和一个IRebatePolicySetter,这样它依赖于抽象,而不是实现。

public interface IRebatePolicySetter
{
     void setPolicyOnOrder(Order order);
}

public class RebatePolicySetter implements IRebatePolicySetter
{
     @Inject 
     Private RebatePolicyFactory rebatePolicyFactory;
     @Inject 
     Private InjectorHelper injector;

     void setPolicyOnOrder(Order order)
     {
          injector.injectDependencies(order);
          order.setRebatePolicy(rebatePolicyFactory.createRebatePolicy());
     }
}

public class JpaOrderRepository implements OrderRepository, IOrderRepository
{
    @Inject 
    Private IRebatePolicySetter rebatePolicySetter;
    @Inject
    IEventPublisher eventPublisher;

    public  void persist(Order order)
    {
         super.persist(order);
         eventPublisher.publish(new OrderCreatedEvent(order.getEntityId())); // This is ok in my book, as long as eventPublisher is an interface.
    }

    Public  Order load(OderId orderId)
    {
        Order order = super.load(orderId);
        rebatePolicySetter.setPolicyOnOrder(order);
        return order;
    }
}

话虽如此,在基础架构代码中,您可以拥有任意数量的依赖项。你可能不应该,并试图尽可能地限制它们,这就是我在这里所做的。但是如果回购需要这些东西来执行它的工作,那么在你的回购中注入依赖关系是没问题的。你不希望你的业务逻辑依赖于事物,所以你让他们使用接口。

但请记住

注意:您的persist方法似乎只进行创建添加。如果您也将它用于更新,那么您的OrderCreatedEvent是否会令人困惑?

注意2:为什么RebatePolicy来自工厂?难道订单的折扣政策的信息不是来自持久层吗?