首页 文章

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

提问于
浏览
1

我正在考虑将DDD用于示例应用程序,现在我仍然坚持使用域事件 . 由于那里有非常好的EventDispatcher,我不想重新发明轮子 . 但是这些实现都要求我的事件正在实现它们的EventInterface . 我想保持我的域事件的实现与任何类型的实现分开 . 我该如何处理这个问题?

2 回答

  • 1

    我能想到的两种可能性

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

    2)使用builder api创建域事件;域定义了构建器 Contract ,但是封面下的实现特定于您正在使用的事件调度程序 .

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

相关问题