提供域事件的默认实现:
表示域事件的接口:
public interface IDomainEvent { }
表示通用域事件处理程序的接口:
public interface IEventHandler<T> where T : IDomainEvent
筹集新活动的中央接入点:
public static class DomainEvents
{
public static void Raise<T>(T event) where T : IDomainEvent
{
//Factory is a IoC container like Ninject. (Service Location/Bad thing)
var eventHandlers = Factory.GetAll<IEventHandler<T>>();
foreach (var handler in eventHandlers )
{
handler.Handle(event);
}
}
}
耗竭与:
public class SaleCanceled : IDomainEvent
{
private readonly Sale sale;
public SaleCanceled(Sale sale)
{
this.sale = sale;
}
public Sale Sale
{
get{ return sale; }
}
}
引发事件的服务:
public class SalesService
{
public void CancelSale(int saleId)
{
// do cancel operation
// creates an instance of SaleCanceled event
// raises the event
DomainEvents.Raise(instanceOfSaleCanceledEvent);
}
}
是否有其他方法可以在不使用服务位置反模式的情况下使用域事件?
答案 0 :(得分:7)
我想在你的情况下,你真的不需要。使用依赖注入,您可以在服务中注入IDomainEventDispatcher
实现。
我之所以认为像这样的单身人士已经成为主流,这是一些着名开发人员首先提出的实现之一,起初并不觉得太错误。另一个原因是可能需要从域内提出事件:
public class Customer
{
public void Enable()
{
_enabled = true;
DomainEvents.Raise(new CustomerEnabledEvent(_id));
}
}
在某个阶段,Jan Kronquist发现了这篇文章:http://www.jayway.com/2013/06/20/dont-publish-domain-events-return-them/
这是我第三次将这个链接添加到我的答案中,因为我必须赞扬这一点以改变我的想法。但是,我想我现在就不再那样做了。对不起Jan:)
所以关键是我们可以将我们的实现改为:
public class Customer
{
public CustomerEnabledEvent Enable()
{
_enabled = true;
return new CustomerEnabledEvent(_id);
}
}
现在我们的服务可以更改为使用注入的调度程序:
public class CustomerService
{
private IDomainEventDispatch _dispatcher;
private ICustomerRepository _customerRepository;
public CustomerService(ICustomerRepository customerRepository, IDomainEventDispatch dispatcher)
{
_customerRepository = customerRepository;
_dispatcher = dispatcher;
}
public void Enable(Guid customerId)
{
_dispatcher.Raise(_customerRepository.Get(customerId).Enable());
}
}
因此不需要单例,您可以愉快地注入依赖项。
答案 1 :(得分:2)
我从未使用过静态DomainPublisher,除了@Eben之外我还有其他参数来处理它。这只是我的个人经历,以下是我想分享的一些原因:
我所做的是拥有要在聚合根实体上发布的事件集合。每次发布一个事件时,它都会被添加到集合中。我将域发布者注入聚合根存储库。因此,事件的发布可以由存储库中的域发布者在基础结构级别处理。由于域名发布者实施经常需要处理队列和总线等中间件,因此基础架构级别是正确处理IMO的正确位置。您可以更轻松地处理有关如何处理发布事件的策略,例如将实体保存到数据库时会出现异常。你不想要的是发布事件而不是保存数据库中的权利,反之亦然。
答案 2 :(得分:1)
如果使用泛型方法EventHandlerFactory
创建类Create<T>
并且T受IEventHandler<T>
类型约束,则此类不会为locator提供服务,而是为factory提供服务,因为您只创建{{1实例。同时服务定位器就像God Object,他知道一切。
有关此here
的更多信息