Steve Gentile recently directed me to Udi Dahan’s recent post his improvement on the Domain Event pattern, and after reading the post, digesting it and thinking about his approach I have decided to include it into NCommon.
The Domain Event pattern aims to provide a solution for being able to create fully encapsulated domain models. The term fully encapsulated domain models refer to the approach where the entities in your domain model are not bound or depend on external services for any purpose or operation.
A good example for this, although a beaten to death example, is the email sending or rather the notification example. Lets say when an order’s status has changed an email notification has to be sent out to the customer of the order informing them of this status change. My previous approach has been to use the Service Locator pattern to get a service instance of IOrderStatsNotifier and use the IOrderStatusNotifier instance to send out the emails.
Semantically that has always bothered me because the domain entity really should not be informing the notifier that the order’s status has changed, rather it should be the other way around. The Notifier should automatically be able to handle order’s status change and do the necessary. With the Domain Events pattern this becomes ridiculously easy.
If you haven’t read Udi’s post, I’d strongly recommend reading it. Anyways, the implementation of Domain Events pattern in NCommon is almost identical to that shown in Udi’s post. Below is a test from NCommon that shows how the Domain Event pattern can be used:
[Test]
public void registered_handlers_are_executed_when_event_is_raised ()
{
var mockTest1Handler = MockRepository.GenerateMock<Handles<TestEvent1>>();
var mockTest2Handler = MockRepository.GenerateMock<Handles<TestEvent2>>();
var locator = MockRepository.GenerateStub<IServiceLocator>();
locator.Expect(x => x.GetAllInstances<Handles<TestEvent1>>())
.Return(new[]{mockTest1Handler});
ServiceLocator.SetLocatorProvider(() => locator);
DomainEvent.Raise(new TestEvent1());
mockTest1Handler.AssertWasCalled(x => x.Handle(null), options => options.IgnoreArguments());
mockTest2Handler.AssertWasNotCalled(x => x.Handle(null), options => options.IgnoreArguments());
}
The implementation of Domain Events pattern is available in trunk.