ASP.NET 设计模式 -- 第14章 订购与支付 (学习笔记)
14.1.1 Order(领域事件框架)
将要创建的领域事件框架基于Udi Dahan(http://www.udidahan.com)设计的框架。
(1)在Agathas.Storefront.Infrastructure项目的Domain文件夹中新建Events文件夹,向其中创建接口IDomainEvent,该接口将标识模型中的领域事件。
namespace Agathas.Storefront.Infrastructure.Domain.Events { public interface IDomainEvent { } }
(2)创建IDomainEventHandler接口,这是事件处理程序必须实现的接口。
namespace Agathas.Storefront.Infrastructure.Domain.Events { public interface IDomainEventHandler<T> where T : IDomainEvent { void Handle(T domainEvent); } }
(3)创建IDomainEventHandlerFactory接口,它是用来获取给定领域事件的领域事件处理程序集合。
namespace Agathas.Storefront.Infrastructure.Domain.Events { public interface IDomainEventHandlerFactory { IEnumerable<IDomainEventHandler<T>> GetDomainEventHandlersFor<T>(T domainEvent) where T : IDomainEvent; } }
(4)添加IDomainEventHandlerFactory接口的一个实现StructureMapDomainEventHandlerFactory,它提供了负责处理给定领域事件的IDomainEventHandler列表。
using System.Collections.Generic; using StructureMap; namespace Agathas.Storefront.Infrastructure.Domain.Events { public class StructureMapDomainEventHandlerFactory : IDomainEventHandlerFactory { public IEnumerable<IDomainEventHandler<T>> GetDomainEventHandlersFor<T> (T domainEvent) where T : IDomainEvent { return ObjectFactory.GetAllInstances<IDomainEventHandler<T>>(); } } }
(5)在获取IDomainEventHandler集合之后,调用它们的处理方法并将领域事件作为动作的实参。添加一个扩展方法IEnumerableExtensions来处理。
using System; using System.Collections.Generic; namespace Agathas.Storefront.Infrastructure.Domain.Events { public static class IEnumerableExtensions { public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) { foreach (T item in source) action(item); } } }
(6)为了引发事件,需要创建一个静态类DomainEvents,Model项目中的领域实体将调用该类。
namespace Agathas.Storefront.Infrastructure.Domain.Events { public static class DomainEvents { public static IDomainEventHandlerFactory DomainEventHandlerFactory { get; set; } public static void Raise<T>(T domainEvent) where T : IDomainEvent { DomainEventHandlerFactory.GetDomainEventHandlersFor(domainEvent) .ForEach(h => h.Handle(domainEvent)); } } }
这样就完成了支持领域事件所需的框架。
因为IOrderState实现引发领域事件,所以现在完成这部分的代码.(代码片段位于Agathas.Storefront.Model\Orders)
(1)创建IOrderState接口
namespace Agathas.Storefront.Model.Orders.States { public interface IOrderState { int Id { get; set; } OrderStatus Status { get; } bool CanAddProduct(); void Submit(Order order); } } //需要建立不同的文件 namespace Agathas.Storefront.Model.Orders.States { public enum OrderStatus { Open = 1, Submitted = 2 } }
(2)为了给所有订单状态提供一个基类,创建OrderState抽象类
namespace Agathas.Storefront.Model.Orders.States { public abstract class OrderState : IOrderState { public virtual int Id { get; set; } public abstract OrderStatus Status { get; } public abstract bool CanAddProduct(); public abstract void Submit(Order order); } }
(3)订单的初始状态为OpenOrderState,当调用Submit方法时,如果订单已经被付款,就引发OrderSubmittedEvent事件。
using Agathas.Storefront.Infrastructure.Domain.Events; using Agathas.Storefront.Model.Orders.Events; namespace Agathas.Storefront.Model.Orders.States { public class OpenOrderState : OrderState { public override OrderStatus Status { get { return OrderStatus.Open; } } public override bool CanAddProduct() { return true; } public override void Submit(Order order) { if (order.OrderHasBeenPaidFor()) order.SetStateTo(OrderStates.Submitted); DomainEvents.Raise(new OrderSubmittedEvent() { Order = order }); } } }
(4)创建上述的OrderSubmittedEvent领域事件
using Agathas.Storefront.Infrastructure.Domain.Events; namespace Agathas.Storefront.Model.Orders.Events { public class OrderSubmittedEvent : IDomainEvent { public Order Order { get; set; } } }
(5)创建这个事件的处理程序OrderSubmittedHandler,它将向顾客发送一封电子邮件告知他们订单现在已经提交。
using System; using System.Text; using Agathas.Storefront.Infrastructure.Domain.Events; using Agathas.Storefront.Infrastructure.Email; using Agathas.Storefront.Model.Orders.Events; namespace Agathas.Storefront.Services.DomainEventHandlers { public class OrderSubmittedHandler : IDomainEventHandler<OrderSubmittedEvent> { public void Handle(OrderSubmittedEvent domainEvent) { StringBuilder emailBody = new StringBuilder(); string emailAddress = domainEvent.Order.Customer.Email; string emailSubject = String.Format("Agatha Order #{0}", domainEvent.Order.Id); emailBody.AppendLine(String.Format("Hello {0},", domainEvent.Order.Customer.FirstName)); emailBody.AppendLine(); emailBody.AppendLine( "The following order will be packed and dispatched as soon as possible."); emailBody.AppendLine(domainEvent.Order.ToString()); emailBody.AppendLine(); emailBody.AppendLine("Thank you for your custom."); emailBody.AppendLine("Agatha's"); EmailServiceFactory.GetEmailService() .SendMail("orders@Agatha.com", emailAddress, emailSubject, emailBody.ToString()); } } }
浙公网安备 33010602011771号