Domain driven design 存储库引发事件和注入依赖项
请查看以下存储库。对于DDD规则,存储库可以注入一些依赖项并引发事件吗?我读到存储库通常属于基础设施,不应该做这样的事情。你认为这种方法怎么样? 也许最好在域服务中包装存储库调用,并在其中执行事件源和依赖注入?:Domain driven design 存储库引发事件和注入依赖项,domain-driven-design,ddd-repositories,Domain Driven Design,Ddd Repositories,请查看以下存储库。对于DDD规则,存储库可以注入一些依赖项并引发事件吗?我读到存储库通常属于基础设施,不应该做这样的事情。你认为这种方法怎么样? 也许最好在域服务中包装存储库调用,并在其中执行事件源和依赖注入?: public class JpaOrderRepository implements OrderRepository{ @Inject Private RebatePolicyFactory rebatePolicyFactory; @Inject Private Injecto
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;
}
}
从存储库中获取的代码是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;
}
}
否则,我认为您没有处理足够的抽象。在核心中,您需要所有存储库、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;
}
}
话虽如此,在基础架构代码中,您可以拥有任意多的依赖项。你可能不应该,尽量限制他们,这就是我在这里做的。但是,如果repo需要这些东西来执行其工作,那么在repo中注入依赖项是可以的。不过,您不希望您的业务逻辑依赖于事物,所以您应该让它们使用接口
但请记住
注意:您的persist方法似乎只执行创建添加。如果您也使用它进行更新,您的OrderCreatedEvent不是很混乱吗
注2:为什么再就业政策来自工厂?订单折扣政策的信息不应该来自持久层吗?存储库属于域层,其实现属于基础架构层。我觉得这个不错。但通常不建议将依赖项注入模型。是的,接口属于域,实现属于基础结构。不建议使用DI,那么事件源呢?我认为您在这里脱离了DDD的整个要点。您的问题中有一个实现,但没有要求。您试图解决的业务问题是什么?我听说存储库的实现不属于这个领域,因为它通常与基础架构相耦合。问题是:在某些方面(属于基础设施的内容)设置依赖项或生成域事件可以吗?根据洋葱/六角形结构,它是允许的。