.NetCore 简化版发布订阅实现

一、发布订阅的作用

业务代码解耦,发布者只需要发布消息,而不用关心这些消息后续被谁处理,以及怎么处理; 订阅者接收到消息通知后,跟据业务需求进行后续的逻辑处理。

二、代码实现分析

第一步:定义委托,用于包裹订阅函数,用于延后执行。

第二步:定义发布及订阅接口

第三步:实现发布订阅接口

第四步:在程序启动项目Startup的ConfigureServices方法中注入单例

第五步:在程序启动项目Startup的Configure方法中启用订阅

三、实现代码

    /// 
    /// 事件委托
    /// 
    /// 
    /// 
    public delegate void TEventHandler(in TEvent @event) where TEvent : class;


    /// 
    /// 事件总线
    /// 
    public interface IEventBus
    {
        /// 
        /// Publishes the event
        /// 
        /// The event type
        /// The event
        void Publish(in TEvent @event) where TEvent : class;

        /// 
        /// Subscribes to the event type
        /// 
        /// The event type
        /// The event type
        /// 
        IDisposable Subscribe(TEventHandler eventHandler) where TEvent : class;
    }
    /// 
    /// 实现类
    /// 
    public sealed class EventBus : IEventBus
    {
        private readonly ILogger logger;
        private readonly ConcurrentDictionary subscriptions = new ConcurrentDictionary();
        private readonly object subscriptionLock = new object();

        public EventBus(ILogger logger)
        {
            this.logger = logger;
        }


        public void Publish(in TEvent @event) where TEvent : class
        {
            if (!subscriptions.TryGetValue(typeof(TEvent), out var handlers))
                return;

            ((Handlers)handlers).Handle(@event);
        }


        public IDisposable Subscribe(TEventHandler eventHandler) where TEvent : class
        {
            if (!subscriptions.TryGetValue(typeof(TEvent), out var handlers))
            {
                lock (subscriptionLock)
                {
                    if (!subscriptions.TryGetValue(typeof(TEvent), out handlers))
                    {
                        handlers = subscriptions[typeof(TEvent)] = new Handlers(logger);
                    }
                }
            }
            var typedHandlers = (Handlers)handlers;
            typedHandlers.Add(eventHandler);
            return new Subscription(typedHandlers, eventHandler);
        }

        private sealed class Handlers where TEvent : class
        {
            private readonly ILogger logger;
            private readonly object mutex = new object();
            private volatile List> handlers = new List>();

            public Handlers(ILogger logger)
            {
                this.logger = logger;
            }

            public void Add(TEventHandler eventHandler)
            {
                lock (mutex)
                {
                    var newHandlers = new List>(handlers);
                    newHandlers.Add(eventHandler);
                    handlers = newHandlers;
                }
            }

            public void Remove(TEventHandler eventHandler)
            {
                lock (mutex)
                {
                    var newHandlers = new List>(handlers);
                    newHandlers.Remove(eventHandler);
                    handlers = newHandlers;
                }
            }

            public void Handle(in TEvent @event)
            {
                // ReSharper disable once InconsistentlySynchronizedField
                foreach (var handler in handlers)
                    try
                    {
                        handler(in @event);
                    }
                    catch (Exception exception)
                    {
                        logger.LogError(exception, $"Failed to handle {@event}");
                    }
            }
        }

        private sealed class Subscription : IDisposable where TEvent : class
        {
            private readonly Handlers handlers;
            private readonly TEventHandler eventHandler;

            public Subscription(Handlers handlers, TEventHandler eventHandler)
            {
                this.handlers = handlers;
                this.eventHandler = eventHandler;
            }

            public void Dispose() => handlers.Remove(eventHandler);
        }
    }

四、调用

// 注入消息总线
services.AddSingleton();


// 使用订阅者
app.GetService().Subscribe((in TEvent businessData) =>{//todo 订阅逻辑})

你可能感兴趣的:(.netcore)