我正在考虑将DDD用于示例应用程序,现在我仍然坚持使用域事件。由于那里有非常好的EventDispatcher,我不想重新发明轮子。但是这些实现都要求我的事件正在实现它们的EventInterface。我想保持我的域事件的实现与任何类型的实现分开。我该如何处理这个问题?
答案 0 :(得分:1)
这是我的意思:
/// <summary>
/// Contains the contract for publishing domain events.
/// </summary>
public interface IDomainEventPublisher
{
/// <summary>
/// Publishes the domain events.
/// </summary>
/// <param name="domainEvents">events to be published</param>
Task Publish(IEnumerable domainEvents);
/// <summary>
/// Subscribes the list of subscribers.
/// </summary>
/// <param name="subscribers">event subscriptions</param>
void Subscribe(params IDomainEventSubscription[] subscribers);
/// <summary>
/// Subscribes to the event.
/// </summary>
/// <typeparam name="T">event to subscribe too</typeparam>
/// <returns>event subscription</returns>
DomainEventSubscription<T> SubscribeTo<T>();
}
/// <summary>
/// Publishes events to registered subscribers.
/// </summary>
public class DefaultDomainEventPublisher : IDomainEventPublisher
{
readonly List<IDomainEventSubscription> subscriptions;
/// <summary>
/// Creates a new instance of the object.
/// </summary>
public DefaultDomainEventPublisher()
{
subscriptions = new List<IDomainEventSubscription>();
}
/// <summary>
/// Subscribes to the event.
/// </summary>
/// <typeparam name="T">event to subscribe too</typeparam>
/// <returns>event subscription</returns>
public DomainEventSubscription<T> SubscribeTo<T>()
{
var subscription = new DomainEventSubscription<T>();
subscriptions.Add(subscription);
return subscription;
}
/// <summary>
/// Subscribes the list of subscribers.
/// </summary>
/// <param name="subscribers">event subscriptions</param>
public void Subscribe(params IDomainEventSubscription[] subscribers)
{
subscriptions.AddRange(subscribers);
}
/// <summary>
/// Publishes the domain events.
/// </summary>
/// <param name="domainEvents">events to be published</param>
public virtual async Task Publish(IEnumerable domainEvents)
{
foreach (var @event in domainEvents)
{
var subscribers = subscriptions.Where(s => s.CanHandleType(@event.GetType()));
foreach (var subscriber in subscribers)
{
await subscriber.Handle(@event);
}
}
}
}
/// <summary>
/// Handles the subscription services for an event.
/// </summary>
/// <typeparam name="T"></typeparam>
public class DomainEventSubscription<T> : IDomainEventSubscription
{
readonly List<object> subscriptionMethods;
/// <summary>
/// Constructs a new instance.
/// </summary>
public DomainEventSubscription()
{
this.subscriptionMethods = new List<object>();
}
/// <summary>
/// Adds the subscription method to the subscription.
/// </summary>
/// <param name="subscriptionMethod">subscription method</param>
public void AddSubscriptionMethod(ISubscriptionMethod subscriptionMethod)
{
subscriptionMethods.Add(subscriptionMethod);
}
/// <summary>
/// Returns whether or not the subscription can handle the specified type.
/// </summary>
/// <param name="type"></param>
/// <returns>whether it can handle the type</returns>
public bool CanHandleType(Type type)
{
return type.IsAssignableFrom(typeof(T));
}
/// <summary>
/// Publishes the event.
/// </summary>
/// <param name="event">event to publish</param>
public async Task Handle(object @event)
{
foreach (var subscriptionMethod in subscriptionMethods)
{
await (subscriptionMethod as dynamic).Handle(@event);
}
}
}
/// <summary>
/// Contains the contract for event subscribers.
/// </summary>
public interface IDomainEventSubscription
{
/// <summary>
/// Publishes the event.
/// </summary>
/// <param name="event">event to publish</param>
Task Handle(object @event);
/// <summary>
/// Returns whether or not the subscription can handle the specified type.
/// </summary>
/// <param name="type"></param>
/// <returns>whether it can handle the type</returns>
bool CanHandleType(Type type);
}
/// <summary>
/// Contacts the contract for subscription methods.
/// </summary>
public interface ISubscriptionMethod
{
/// <summary>
/// Publishes the event.
/// </summary>
/// <param name="event">event to publish</param>
Task Handle(object @event);
}
/// <summary>
/// Base class for subscription method implementations.
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class SubscriptionMethod : ISubscriptionMethod
{
/// <summary>
/// Publishes the event.
/// </summary>
/// <param name="event">event to publish</param>
public abstract Task Handle(object @event);
}
/// <summary>
/// Publishes events using delegates.
/// </summary>
/// <typeparam name="T"></typeparam>
public class DelegateSubscriptionMethod<T> : ISubscriptionMethod
{
readonly Func<T, Task> delegateAction;
/// <summary>
/// Constructs a new instance.
/// </summary>
/// <param name="action">delegate used for publishing</param>
public DelegateSubscriptionMethod(Func<T, Task> action)
{
delegateAction = action;
}
/// <summary>
/// Publishes the event using a delegate.
/// </summary>
/// <param name="event">event to publish</param>
public async Task Handle(object @event)
{
await delegateAction(@event as dynamic);
}
}
/// <summary>
/// Provides an extension method for publishing an event using a delegate.
/// </summary>
public static class DomainEventSubscriptionExtensions
{
/// <summary>
/// Adds an event subscription for publishing using the specified delegate.
/// </summary>
/// <typeparam name="T">event the subscription is subscribed too</typeparam>
/// <param name="subscription">event subscription</param>
/// <param name="action">delegate used for publishing</param>
/// <returns>event subscription</returns>
public static DomainEventSubscription<T> UsingDelegate<T>(this DomainEventSubscription<T> subscription, Func<T, Task> action)
{
var subscriptionMethod = new DelegateSubscriptionMethod<T>(action);
subscription.AddSubscriptionMethod(subscriptionMethod);
return subscription;
}
}
以下是一些基本用法:
publisher.SubscribeTo<DocumentOwnerChanged>()
.UsingDelegate(
async a => await messageGateway.DocumentOwnerChanged(1, 1, 1));
我还有一个使用我的DI容器自动订阅的实现。如果你想看到这个,请告诉我。
答案 1 :(得分:1)
我能想到的两种可能性
1)在EventDispatcher前面介绍适配器的概念;适配器接受域生成的格式的事件,&#34;序列化&#34;将相同的数据放入您正在使用的特定调度程序实现所需的表单中。
2)使用builder api创建域事件;域定义了构建器合同,但是封面下的实现特定于您正在使用的事件调度程序。