如何在使用供应商事件调度程序时不在域上下文中使用依赖关系



我正在研究将DDD用于示例应用程序,目前我还停留在DomainEvents上。既然有相当好的EventDispatcher,我不想重新发明轮子。但是这些实现都要求我的事件实现它们的EventInterface。我想将我的域事件的实现与任何类型的实现分开。我应该如何处理这个问题?

我能想到的两种可能性

1) 在EventDispatcher前面介绍适配器的想法;适配器接受域生成的格式的事件,并将相同的数据"序列化"为您正在使用的特定调度器实现所需的格式。

2) 使用构建器api创建域事件;域定义了构建器契约,但是所涵盖的实现是特定于您正在使用的事件调度器的。

这是我的impl:

/// <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容器自动订阅的实现。如果你也想看这个,请告诉我。

最新更新