[英]Domain Events without Service Locator
Giving the default implementation of Domain Events: 提供域事件的默认实现:
Interface that represents an domain event: 表示域事件的接口:
public interface IDomainEvent { }
Interface that represents a generic domain event handler: 表示通用域事件处理程序的接口:
public interface IEventHandler<T> where T : IDomainEvent
Central access point to raise new events: 筹集新活动的中央接入点:
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);
}
}
}
Consuming: 消费:
public class SaleCanceled : IDomainEvent
{
private readonly Sale sale;
public SaleCanceled(Sale sale)
{
this.sale = sale;
}
public Sale Sale
{
get{ return sale; }
}
}
Service that raises the event: 提升活动的服务:
public class SalesService
{
public void CancelSale(int saleId)
{
// do cancel operation
// creates an instance of SaleCanceled event
// raises the event
DomainEvents.Raise(instanceOfSaleCanceledEvent);
}
}
Is there another approach to use Domain Events without use of Service Location anti-pattern? 是否有另一种方法可以在不使用服务位置反模式的情况下使用域事件?
I guess in your case you really do not have to. 我想在你的情况下,你真的不需要。 Using dependency injection you could inject a
IDomainEventDispatcher
implementation into your service. 使用依赖注入,您可以将
IDomainEventDispatcher
实现注入到您的服务中。
The reason why I think a singleton like this has made it into the mainstream it was one of the first implementations to be proposed by some prominent developers and at first it doesn't feel too wrong. 我之所以认为像这样的单身人士已经成为主流,它是一些着名开发人员提出的首批实现之一,起初并不觉得太错误。 The other reason is that events may need to be raised from within the domain:
另一个原因是可能需要从域内引发事件:
public class Customer
{
public void Enable()
{
_enabled = true;
DomainEvents.Raise(new CustomerEnabledEvent(_id));
}
}
At some stage I came across this post by Jan Kronquist: http://www.jayway.com/2013/06/20/dont-publish-domain-events-return-them/ 在某些阶段,Jan Kronquist发现了这篇文章: http : //www.jayway.com/2013/06/20/dont-publish-domain-events-return-them/
This is the third time I have added that link to my answers since I have to give credit to this for changing my thinking. 这是我第三次将这个链接添加到我的答案中,因为我必须赞扬这一点以改变我的想法。 However, I think I'll stop doing that now.
但是,我想我现在就不再那样做了。 Sorry Jan :)
对不起Jan :)
So the point is that we can change our implementation to the following: 所以关键是我们可以将实现更改为以下内容:
public class Customer
{
public CustomerEnabledEvent Enable()
{
_enabled = true;
return new CustomerEnabledEvent(_id);
}
}
Now our service can be changed to use an injected dispatcher: 现在我们的服务可以更改为使用注入的调度程序:
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());
}
}
So no singleton is required and you can happily inject the dependency. 所以不需要单例,你可以愉快地注入依赖。
I have never used a static DomainPublisher and I have other arguments than @Eben on how I handle it. 我从未使用过静态DomainPublisher,除了@Eben之外我还有其他参数来处理它。 This is just my personal experience and here are some of the reasons that I want to share :
这只是我的个人经历,以下是我想分享的一些原因:
What I do, is to have a collection of events to publish on the aggregate root entity. 我所做的是在聚合根实体上发布要发布的事件集合。 Each time an event should be published, it is just added to the collection.
每次发布一个事件时,它都会被添加到集合中。 I inject the domain publisher into the aggregate root repository.
我将域发布者注入聚合根存储库。 Thus publishing of events can be handled at the infrastructure level by the domain publisher in the repository.
因此,事件的发布可以由存储库中的域发布者在基础结构级别处理。 Because a domain publisher implementation very often has to deal with middleware like queues and buses, infrastructure level is right place to handle it correctly IMO.
由于域名发布者实施经常需要处理队列和总线等中间件,因此基础架构级别是正确处理IMO的正确位置。 You can more easily deal with strategies of how you deal with publishing events when for example there is an exception when saving your entity to the database.
您可以更轻松地处理有关如何处理发布事件的策略,例如将实体保存到数据库时会出现异常。 What you would not want is to publish events and not save entitites in your database or the other way round.
您不希望的是发布事件而不是保存数据库中的权限或反之。
If you create class EventHandlerFactory
with generic method Create<T>
and T is constrained by IEventHandler<T>
type, then this class will not service locator, but factory, because you create only IEventHandler<T>
instances. 如果使用泛型方法
Create<T>
创建类EventHandlerFactory
并且T由IEventHandler<T>
类型约束,则此类不会为locator提供服务,而是为factory提供服务,因为您只创建IEventHandler<T>
实例。 At the same time Service locator is like God Object , he know everything. 同时服务定位器就像上帝对象 ,他知道一切。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.