zoukankan      html  css  js  c++  java
  • 事件总线demo

    经过几天的努力拜读大牛高手文章,终于对事件总线有所了解,特此记录下来,以免忘记

    1、定义相关的接口:

      A  事件接口

     1 public interface IDomainEvent
     2     {
     3         DateTime OccurredOn();
     4 
     5         /// <summary>
     6         /// 设置为已读
     7         /// </summary>
     8         /// <returns></returns>
     9         void Read();
    10 
    11         /// <summary>
    12         /// 是否已读
    13         /// </summary>
    14         bool IsRead { get; }
    15     }

      B  事件订阅接口

        public interface IDomainEventSubscriber
        {
            Type SubscribedToEventType();
    
            void Handle(object domainEvent);
        }

    2、定义相关实现

      A  事件实现

     public abstract class DomainEvent :  IDomainEvent
        {
            public readonly DateTime OccurredOnTime;
            public string ID;
    
            protected DomainEvent()
            {
                this.ID = Guid.NewGuid().ToString();
                this.OccurredOnTime = DateTime.Now;
                this.IsRead = false;
            }
    
            public DateTime OccurredOn()
            {
                return this.OccurredOnTime;
            }
    
            public void Read()
            {
                this.IsRead = true;
            }
    
            public bool IsRead { get; private set; }
        }

      B  事件订阅实现

        public abstract class DomainEventSubscriber<T> : IDomainEventSubscriber where T : IDomainEvent
        {
            /// <summary>订阅的事件类型
            /// </summary>
            /// <returns></returns>
            public Type SubscribedToEventType()
            {
                return typeof(T);
            }
    
            public abstract void HandleEvent(T domainEvent);
    
            public void Handle(object domainEvent)
            {
                if (domainEvent is T)
                {
                    this.HandleEvent((T)domainEvent);
                }
                else
                {
                    throw new NotSupportedException(string.Format("当前订阅者支持的事件类型是:{0},当前事件是:{1}", typeof(T).FullName, domainEvent.GetType().FullName));
                }
            }
        }

    3、定义事件总线实现

     public class DomainEventBus
        {
            public delegate void DistributeExceptionHandle(IDomainEventSubscriber subscriber, IDomainEvent domainEvent, Exception exception);
            /// <summary>
            /// Key:DomainEvent的类型,Value订阅该类型事件的订阅者列表
            /// </summary>
            private static readonly Dictionary<Type, List<IDomainEventSubscriber>> _subscribers = new Dictionary<Type, List<IDomainEventSubscriber>>();
    
            private static readonly object _lockObj = new object();
    
            public event DistributeExceptionHandle DistributeExceptionEvent;
    
            private static DomainEventBus _instance;
            public static DomainEventBus Instance()
            {
                if (_instance != null)
                    return _instance;
                var temp = new DomainEventBus();
                Interlocked.CompareExchange(ref _instance, temp, null);
                return temp;
            }
    
            public void Publish<T>(T aDomainEvent) where T : IDomainEvent
            {
                if (aDomainEvent.IsRead)
                    return;
    
                var registeredSubscribers = _subscribers;
                if (registeredSubscribers != null)
                {
                    var domainEventType = aDomainEvent.GetType();
                    List<IDomainEventSubscriber> subscribers;
                    if (!registeredSubscribers.TryGetValue(domainEventType, out subscribers))
                    {
                        aDomainEvent.Read();  //未找到订阅者,但是消息还是消费掉。
                        return;
                    }
    
                    foreach (var domainEventSubscriber in subscribers)
                    {
                        var subscribedTo = domainEventSubscriber.SubscribedToEventType();
                        if (subscribedTo == domainEventType || subscribedTo is IDomainEvent)
                        {
                            Distribute(domainEventSubscriber, aDomainEvent);
                        }
                    }
    
                    aDomainEvent.Read();
                }
            }
    
            private void Distribute(IDomainEventSubscriber subscriber, IDomainEvent domainEvent)
            {
                try
                {
                    subscriber.Handle(domainEvent);
                }
                catch (Exception ex)
                {
                    OnDistributeExceptionEvent(subscriber, domainEvent, ex);
                }
            }
    
            public void Subscribe(IDomainEventSubscriber aSubscriber)
            {
                lock (_lockObj)
                {
                    var registeredSubscribers = _subscribers;
    
                    var domainEventType = aSubscriber.SubscribedToEventType();
                    List<IDomainEventSubscriber> subscribers;
    
                    if (!registeredSubscribers.TryGetValue(domainEventType, out subscribers))
                    {
                        subscribers = new List<IDomainEventSubscriber>();
                        registeredSubscribers.Add(domainEventType, subscribers);
                    }
    
                    if (subscribers.Any(ent => ent.SubscribedToEventType().FullName == aSubscriber.SubscribedToEventType().FullName && ent.GetType().FullName == aSubscriber.GetType().FullName))  //相同的订阅只接收一次。
                        return;
    
                    subscribers.Add(aSubscriber);
                }
            }
    
            protected virtual void OnDistributeExceptionEvent(IDomainEventSubscriber subscriber, IDomainEvent domainEvent, Exception exception)
            {
                var handler = DistributeExceptionEvent;
                if (handler != null)
                    handler(subscriber, domainEvent, exception);
            }
        }

    4、定义具体的事件

    public class OrderCreated : DomainEventCore.DomainEvent
        {
            public string OrderId { get; private set; }
    
            public string UserId { get; private set; }
    
            public string Receiver { get; private set; }
    
            public OrderCreated(string orderId, string userId, string receiver)
            {
                this.OrderId = orderId;
                this.UserId = userId;
                this.Receiver = receiver;
            }
        }
    View Code

    5、定义具体事件触发后要执行的方法

     public class OrderCreatedSubscriberPaymentContext : DomainEventSubscriber<OrderCreated>
        {
            public override void HandleEvent(OrderCreated domainEvent)
            {
                //TODO anything
                Console.WriteLine("Order ID:{0},i have payment",domainEvent.OrderId);
            }
        }
    View Code
     public class OrderCreatedSubscriberSellingPriceContext : DomainEventSubscriber<OrderCreated>
        {
            public override void HandleEvent(OrderCreated domainEvent)
            {
                //TODO anything
                Console.WriteLine("Order ID:{0},i have show price", domainEvent.OrderId);
            }
        }
    View Code

    6、代码测试

    class Program
        {
            static void Main(string[] args)
            {
                //事件订阅
                DomainEventBus.Instance().Subscribe(new OrderCreatedSubscriberSellingPriceContext());
                DomainEventBus.Instance().Subscribe(new OrderCreatedSubscriberPaymentContext());
    
                var tempGuid = Guid.NewGuid().ToString();
                var entity = new OrderCreated(tempGuid, "mikechang", "sprite");
                Console.WriteLine("生产一个新的订单:{0}",tempGuid);
                //事件发布
                DomainEventBus.Instance().Publish(entity);
                Console.ReadLine();
            }
        }
  • 相关阅读:
    Linux Docker容器磁盘出现日志/var/lib/docker/overlay2占用100%
    (转)关于文字放大缩小
    Jquery 点击按钮切换div(可循环轮播)
    C#调用C++的dll两种方法(托管与非托管)
    Spring——项目优雅停机
    Maven——(mavenantrunplugin、mavendependencyplugin)插件的使用
    微信开放平台第三方平台开发的一些坑解决以备忘 编程
    QRCodeEncoder 生成二维码提示 数组越界 的解决方法 编程
    jenkins+docker+nginx+vue前端项目实现自动部署
    nginx+vue项目请求后端接口报错:405 not allowed
  • 原文地址:https://www.cnblogs.com/mikechang/p/6390434.html
Copyright © 2011-2022 走看看