Domain driven design 域事件能否向UI层返回反馈信息?
我对DDD应用程序还是相当陌生的。我正在读埃里克·埃文的“领域驱动设计”,读过Udi Dahan的 但有一件事我搞不清楚,关于域事件成功或失败完成的信息应该如何作为反馈返回给用户(即UI层) 例如,我们可以有以下应用层代码:Domain driven design 域事件能否向UI层返回反馈信息?,domain-driven-design,Domain Driven Design,我对DDD应用程序还是相当陌生的。我正在读埃里克·埃文的“领域驱动设计”,读过Udi Dahan的 但有一件事我搞不清楚,关于域事件成功或失败完成的信息应该如何作为反馈返回给用户(即UI层) 例如,我们可以有以下应用层代码: // Application Layer public void SubmitOrder(OrderData data) { var customer = GetCustomer(data.CustomerId); var shoppingCart = GetSh
// 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...
}
}
}
公共类CustomerPurchaseCompletedHandler:句柄
{
公共无效句柄(CustomerPurchaseCompleted参数)
{
如果(args.Customer.Email!=null){
//向args.Customer发送电子邮件
}
否则{
//报告将不发送电子邮件。。。
}
}
}
我的问题是:我应该如何向用户界面层“冒泡”一条反馈消息,说因为客户没有电子邮件集,所以不会发送电子邮件
我今天看到的选项大致如下:
UserHasNoEmailException
,并在某处捕获该信息。这是非常糟糕的,因为不应该使用异常返回信息,而且这不是致命错误,不应该中止其他处理程序提交者()返回一些列表
。这需要更改Purchase()
和DomainEvents.Raise()
方法才能返回此列表。这导致域模型知道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....
}
}
}
公共类通知CustomerPurchaseCompletedHandler:句柄
{
公共IEventAggregator事件{get;set;}
公共无效句柄(CustomerPurchaseCompleted参数)
{
如果(args.Customer.Email==null){
//通知用户界面
此.Events.GetEvent。。。。
}
}
}
总的来说,这基本上是方法1。的确,UI层现在知道要发送电子邮件,但是UI必须知道这一点,因为它需要呈现一条声明不发送电子邮件的消息。显示消息是一个UI问题,通过将处理程序实现保留为UI层的一部分,您可以将其保留为UI层的一部分。这种方法的问题在于,您要检查客户是否有两次电子邮件。此外,电子邮件的发送与UI通知没有直接联系
另一种选择是引入另一个事件,以表明没有电子邮件的客户已完成购买。然后UI可以订阅此事件。这种方法的缺点是,您专门为UI需求创建事件,而不是为了表达领域知识。事件不应报告反馈。事件是反馈 在这种情况下,
电子邮件
是一项业务需求。因此,customer.Purchase(shoppingCart)如果未指定电子邮件,code>应该确实引发异常
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...
}
}
}
但假设实际的电子邮件传递失败了。我通常做的是创建一个用于通知的域模型。所以我这样做:
var notification = new Notification(userId, "Failed to deliver receipt to user.");
notificationRepository.Save(noitification);
这反过来会生成一个NotificationCreated
事件,该事件可由UI拾取。选项1。这很好,因为它应该知道“那”是用例成功所必需的。。。正如某些错误可能不是致命的,但仍需要向用户报告。对于选项1,用户界面必须知道可能发生的每一种变体。我们不是又回到了一个“万事通”的大应用程序了吗?你需要学习什么是真正的不变量,不要用他们无法修复的东西来打扰最终用户。所以,不,这是用例成功的必要条件。谢谢,那么在调用submitor()
之前,UI(ASP.NET MVC)会注册它自己的事件处理程序吗?这一秒可能只是将ViewModel中的某些属性设置为true或false,对吗?我将尝试理解您提供的EventAggregator
链接,但我不确定它与事件注册过程有何区别…特定于UI的处理程序将在整个应用程序的配置区域中注册,可能在注册原始CustomerPurchaseCompletedHandler
的同一位置。在调用SubmitOrder()
之前不会注册它,因为在应用程序的生命周期中,该调用可能会发生多次,并且继续注册处理程序是没有意义的。特定于UI的处理程序可以在某些ViewModel中设置属性。我提出的事件聚合器将是实现这一点的一种更为解耦的方法—处理程序不再需要耦合到特定的ViewModel实例。我仍然不知道这将如何在我的应用程序中实现,因为域模型层位于UI层的下面:ASP.NET MVC-->Web Service API-->应用层-->域模型。但你的回答确实有道理……:)如果MVC项目与域层e通信