2014-10-31 38 views
7

Tôi đã thực hiện mô hình sau bởi jbogard:Làm cách nào để xử lý các sự kiện miền được xử lý bởi trình xử lý sự kiện?

http://lostechies.com/jimmybogard/2014/05/13/a-better-domain-events-pattern/

Hãy tưởng tượng sau đây thực thể Coupon và sự kiện CouponActivatedEvent:

public class Coupon : DomainEntity 
{ 
    public virtual User User { get; private set; } 

    // ...omitted... 

    public void Activate(User user) 
    { 
     if (User != null) 
      throw new InvalidOperationException("Coupon already activated"); 

     User = user; 

     Events.Add(new CouponActivatedEvent(this)); 
    } 
} 

Việc xử lý sự kiện sau đây CouponActivatedHandler:

public class CouponActivatedHandler : IDomainEventHandler<CouponActivatedEvent> 
{ 
    public void Handle(CouponActivatedEvent e) 
    { 
     // user gets 5 credits because coupon was activated 
     for (int i = 0; i < 5; i++) 
     { 
      e.Coupon.User.AddCredit(); // raises UserReceivedCreditEvent and CreditCreatedEvent 
     } 
    } 
} 

sauoverride trên DbContext (Entity Framework 6), lấy từ bài viết trên blog của jbogard:

public override int SaveChanges() 
{ 
    var domainEventEntities = ChangeTracker.Entries<IDomainEntity>() 
     .Select(po => po.Entity) 
     .Where(po => po.Events.Any()) 
     .ToArray(); 

    foreach (var entity in domainEventEntities) 
    { 
     var events = entity.Events.ToArray(); 
     entity.Events.Clear(); 
     foreach (var domainEvent in events) 
     { 
      _dispatcher.Dispatch(domainEvent); 
     } 
    } 

    return base.SaveChanges(); 
} 

Nếu bây giờ chúng ta kích hoạt một phiếu giảm giá, điều này sẽ nâng cao CouponActivatedEvent. Khi gọi SaveChanges, trình xử lý sẽ được thực thi và UserReceivedCreditEventCreditCreatedEvent sẽ được nâng lên. Họ sẽ không được xử lý mặc dù. Tôi có hiểu lầm về mô hình không? Hoặc là ghi đè SaveChanges không thích hợp?

Tôi đã cân nhắc tạo vòng lặp sẽ lặp lại cho đến khi không có sự kiện mới được nâng lên trước khi chuyển sang base.SaveChanges(); ... nhưng tôi lo rằng mình sẽ vô tình tạo vòng lặp vô tận. Giống như vậy:

public override int SaveChanges() 
{ 
    do 
    { 
     var domainEventEntities = ChangeTracker.Entries<IDomainEntity>() 
      .Select(po => po.Entity) 
      .Where(po => po.Events.Any()) 
      .ToArray(); 

     foreach (var entity in domainEventEntities) 
     { 
      var events = entity.Events.ToArray(); 
      entity.Events.Clear(); 
      foreach (var domainEvent in events) 
      { 
       _dispatcher.Dispatch(domainEvent); 
      } 
     } 
    } 
    while (ChangeTracker.Entries<IDomainEntity>().Any(po => po.Entity.Events.Any())); 

    return base.SaveChanges(); 
} 

Trả lời

12

Vâng, bạn hiểu nhầm mọi thứ. Sự kiện miền không giống như sự kiện C#, đó là thông báo về những gì đã thay đổi trong Miền. Một quy tắc là một sự kiện là một cái gì đó đã xảy ra, đó là trong quá khứ. Do đó, một trình xử lý sự kiện đơn giản là không thể (nó không nên) thay đổi sự kiện, nó giống như thay đổi quá khứ.

Bạn CouponActivatedHandler nên ít nhất có được đơn vị tài tạo thành một kho lưu trữ sau đó cập nhật nó với số lượng tín dụng, sau đó lưu nó, sau đó xuất bản một UserCreditsAdded sự kiện. Thậm chí tốt hơn, trình xử lý chỉ cần tạo và gửi lệnh AddCreditsToUser.

Với mẫu Sự kiện miền, thao tác chỉ đơn giản là chuỗi lệnh-> event-> command-> event etc. Trình xử lý sự kiện thường là dịch vụ (hoặc phương thức trong một) chỉ xử lý bit đó. Người gửi sự kiện sẽ không biết gì về người xử lý và ngược lại.

Như quy tắc ngón tay cái, đối tượng Miền tạo sự kiện khi trạng thái của nó đã thay đổi. Một dịch vụ sẽ thực hiện các sự kiện đó sau đó gửi chúng đến một bus dịch vụ (cho một ứng dụng đơn giản, DI Container là đủ).).

Không bao giờ quên rằng Sự kiện miền là mẫu cao cấp được sử dụng khi thực hiện kiến ​​trúc ứng dụng, nó không chỉ là một cách khác để thực hiện các sự kiện đối tượng (như sự kiện của C#).

+0

Cảm ơn, bạn đã làm rõ nhiều điều cho tôi. Bạn có biết một dự án ví dụ được thiết kế theo cách bạn mô tả không? Tôi nghĩ rằng tôi có được ý tưởng, tôi chỉ không chắc chắn làm thế nào để thực hiện nó đúng cách. – Korijn

+4

Ví dụ, không thực sự. Nhưng bắt đầu thực hiện nó, thực hành làm cho hoàn hảo. Làm, nhận thấy những gì cảm thấy cồng kềnh, cố gắng refactor vv DDD được học bằng cách làm nó. – MikeSW

+0

Tôi nhận được nó ngay bây giờ, cụ thể là * xử lý sự kiện phản ứng với những điều đã xảy ra trong quá khứ * giải thích rất nhiều. – Korijn

Các vấn đề liên quan