3

我对 DDD 应用程序还很陌生。我正在阅读 Eric Evan 的“领域驱动设计”,并阅读了 Udi Dahan的“领域事件拯救”中的“使用领域模型模式”……

我无法弄清楚的一件事是如何将有关领域事件成功或不成功完成的信息作为反馈返回给用户(即 UI 层)?

例如,我们可以有以下应用层代码:

// Application Layer
public void SubmitOrder(OrderData data)
{ 
  var customer = GetCustomer(data.CustomerId);
  var shoppingCart = GetShoppingCart(data.CartId);
  customer.Purchase(shoppingCart);
}

// Domain Model
public class Customer
{ 
   public void Purchase(ShoppingCart cart)
   {
      // something done with the cart...

      DomainEvents.Raise(new CustomerPurchaseCompleted() { Customer = this, ShoppingCart = cart });
   }
}

现在假设我们有以下事件处理程序,如果客户指定了电子邮件地址,它会向客户发送确认电子邮件。

public class CustomerPurchaseCompletedHandler : Handles<CustomerPurchaseCompleted>
{ 
   public void Handle(CustomerPurchaseCompleted args)
   {
      if (args.Customer.Email != null) {
         // send email to args.Customer
      }
      else {
         // report that no email will be sent...
      }
   }
}

我的问题是:我应该如何向 UI 层“冒泡”反馈消息说因为客户没有设置电子邮件而不会发送电子邮件?

我今天看到的选项大致如下:

  1. 让 UI 层检查客户是否有电子邮件,并根据消息做出相应反应。这似乎很糟糕,因为 UI 会知道应该发送一封电子邮件,这是一个应用程序级别的信息。

  2. UserHasNoEmailException在没有电子邮件的情况下抛出一个并在某处捕获该信息。这真的很糟糕,因为不应该使用异常来返回信息,而且它不是致命错误,也不应该中止其他处理程序......

  3. SubmitOrder()回报一些List<FeedbackMessage>。这将需要更改Purchase()DomainEvents.Raise()方法以也返回此列表。这导致领域模型知道 UI 不应该显示什么......

这三个选项似乎都不是很好和实用的。那么 DDD 专家是如何做到的呢?

谢谢。

4

2 回答 2

1

另一个选择是实现另一个事件处理程序,该处理程序专门负责通知 UI 客户没有电子邮件地址。因此,如果 CustomerPurchaseCompletedHandler 不发送电子邮件,则此处理程序将通知 UI。这个处理程序将是 UI 层的一部分。通知 UI 的一个好方法是将事件聚合器注入此处理程序:

public class NotifyingCustomerPurchaseCompletedHandler : Handles<CustomerPurchaseCompleted>
{ 
   public IEventAggregator Events { get; set; }

   public void Handle(CustomerPurchaseCompleted args)
   {
      if (args.Customer.Email == null) {
         // notify UI
         this.Events.GetEvent....
      }
   }
}

总的来说,这本质上是方法 1。确实,UI 层现在知道要发送电子邮件,但是 UI 无论如何都必须具有该知识,因为它需要呈现一条消息,说明不发送电子邮件。显示消息是 UI 问题,通过将处理程序实现保留为 UI 层的一部分,您可以保留它。这种方法的问题在于您要检查客户是否有两次电子邮件。此外,电子邮件的发送不直接与 UI 通知相关联。

另一种选择是引入另一个事件以指示为没有电子邮件的客户完成了购买。然后 UI 可以订阅此事件。这种方法的缺点是您正在创建一个专门针对 UI 要求的事件,而不是表达领域知识。

于 2012-11-14T18:20:24.280 回答
0

事件不应报告反馈。事件是反馈。

在这种情况下,这Email是业务需求。因此,customer.Purchase(shoppingCart);如果未指定电子邮件,则应该真的抛出异常。

但是,假设实际的电子邮件传递失败。我通常做的是创建一个用于通知的域模型。所以我这样做:

var notification = new Notification(userId, "Failed to deliver receipt to user.");
notificationRepository.Save(noitification);

这反过来会生成一个NotificationCreated可以被 UI 拾取的事件。

于 2012-11-15T09:20:08.323 回答