Как доменные события отправляются из доменных объектов? - PullRequest
0 голосов
/ 25 октября 2018

Доменные объекты не должны иметь каких-либо зависимостей, следовательно, также не нужно вводить зависимости.Однако при отправке событий домена изнутри объектов домена я, вероятно, захочу использовать централизованный EventDispatcher.Как я мог получить один?

Я не хочу возвращать список событий вызывающей стороне, поскольку я хотел бы, чтобы они оставались непрозрачными и гарантировали их отправку.Эти события должны использоваться только другими объектами и службами домена, которым необходимо обеспечить возможное согласованное ограничение.

Ответы [ 3 ]

0 голосов
/ 26 октября 2018

См. События домена Udi Dahan

По сути, вы регистрируете один или несколько обработчиков для событий вашего домена, а затем создаете событие, подобное этому:

public class Customer
{
   public void DoSomething()
   {
      DomainEvents.Raise(new CustomerBecamePreferred() { Customer = this });
   }
}

И все зарегистрированные обработчики будут выполнены:

public void DoSomethingShouldMakeCustomerPreferred()
{
   var c = new Customer();
   Customer preferred = null;

   DomainEvents.Register<CustomerBecamePreferred>(p => preferred = p.Customer);

   c.DoSomething();
   Assert(preferred == c && c.IsPreferred);
}

Это в основном реализация Голливудского принципа (Не звоните нам, мы будем называть вас ), так как вы не вызываете обработчик событий напрямую - вместо этого обработчики событий выполняются при возникновении события.

0 голосов
/ 26 октября 2018

Я, вероятно, захочу использовать централизованный EventDispatcher.Как я могу получить один из них?

Передать его в качестве аргумента.

Вероятно, он не будет выглядеть как EventDispatcher, но вместо этого будет похож на некоторую доменную службу, которая описываеттребуемая возможность в конкретных предметных терминах.При составлении приложения вы выбираете, какую реализацию сервиса использовать.

0 голосов
/ 25 октября 2018

Вы просите, чтобы это было в обоих направлениях.Вам либо нужно внедрить зависимость или инвертировать элемент управления и позволить другому объекту управлять взаимодействием между Aggregate и EventDispatcher.Я рекомендую сохранять ваши Агрегаты как можно более простыми, чтобы они не содержали зависимостей и оставались также тестируемыми.

Следующий пример кода очень прост и не будет тем, что вы вводите в производство, но иллюстрирует, как создавать агрегаты, свободные от зависимостей, без передачи списка событий вне контекста, в котором они нужны.

Если у вашего Агрегата есть список событий внутри него:

class MyAggregate 
{
    private List<IEvent> events = new List<IEvent>();

    // ... Constructor and event sourcing?

    public IEnumerable<IEvent> Events => events;

    public string Name { get; private set; }

    public void ChangeName(string name)
    {
        if (Name != name) 
        { 
            events.Add(new NameChanged(name); 
        }
    }
}

Тогда у вас может быть обработчик, который выглядит следующим образом:

public class MyHandler 
{
    private Repository repository;

    // ... Constructor and dependency injection

    public void Handle(object id, ChangeName cmd)
    {
        var agg = repository.Load(id);
        agg.ChangeName(cmd.Name);
        repository.Save(agg);
    }
}

И репозиторий, который выглядиткак:

class Repository
{
    private EventDispatcher dispatcher;

    // ... Constructor and dependency injection

    public void Save(MyAggregate agg)
    {
        foreach (var e in agg.Events)
        {
            dispatcher.Dispatch(e);                
        }
    }
}
...