zoukankan      html  css  js  c++  java
  • EventAggregator, EventBus的实现

    系列主题:基于消息的软件架构模型演变

    .net中事件模型很优雅的实现了观察者模式,同时被大量的使用在各种框架中。如果我们非要给事件模型挑毛病,我觉得有两点:

    • 实现起来略微繁琐
    • 正如我们上篇文章分析,事件模型在特定的情况下会发生内存泄漏

    于是我们想到了更加简单易用的模型:EventAggregator,正如该名称所描述,EventAggregator将观察者都聚合在一个容器里,向EventAggregator发布一个主题,EventAggregator会找到对该主题感兴趣的观察者并通知他。

    IC245765

    Prism框架中实现了一个典型的EventAggregator,有时候我们又把此类实现叫做EventBus。

    MVVM Light中实现了一个叫Messenger的bus,Messenger是EventBus、EventAggregator等概念的抽象,因为此时的主题已经表现的像是消息一样,所以Messenger这一名称也更加靠近基于消息架构这一主题。

    一、实现一个简单的EventBus

    EventBus的职责有两点:

    • 注册观察者
    • 发布主题

    所以接口定义为:

        public interface ISimpleEventBus
        {
            void Register<TEvent>(Action<TEvent> action);
            void Publish<TEvent>(TEvent @event);
        }
    

    所有的主题都可以用Action<TEvent> action来表示,实现起来也很简单:

        public class SimpleEventBus
        {
            public static ConcurrentDictionary<Type,List<Action<object>>> Dictionary=new ConcurrentDictionary<Type, List<Action<object>>>();
     
            public void Register<TEvent>(Action<TEvent> action)
            {
                List<Action<object>> actionList;
                if (!Dictionary.TryGetValue(typeof (TEvent), out actionList))
                {
                    actionList=new List<Action<object>>();
                    Dictionary[typeof (TEvent)] = actionList;
                }
                actionList.Add(o=>action((TEvent)o));
            }
    
            public void Publish<TEvent>(TEvent @event)
            {
                List<Action<object>> actionList;
                if (Dictionary.TryGetValue(typeof (TEvent), out actionList))
                {
                    foreach (var action in actionList)
                    {
                        action(@event);
                    }
                }
            }
        }
    

    EventBus内部通过一个类型为ConcurrentDictionary<Type,List<Action<object>>> 的字典来存储主题和观察者列表。写个测试试试:

            [Test]
            public void Should_handle_registered_action()
            {
                var eventBus = new SimpleEventBus();
    
                var number = 0;
                eventBus.Register<MessageA>(m=>number=m.Number);
                eventBus.Publish(new MessageA(2));
    
                number.Should().Be(2);
            }
    
            internal class MessageA
            {
                public MessageA(int number)
                {
                    Number = number;
                }
                public int Number { get; private set; }
            }
    

    我们自己写的这个simpleEventBus已经能够应付大部分情况了,使用起来也比事件模型简单很多。但是仍然没有解决内存泄漏的问题。

    二、MVVM Light中Messenger的实现

    Messenger的实现是我们这个简单eventBus的升级版,首先他抽象了概念,从事件到消息是思维的一个转变,Messenger认为所有注册的主题都是消息。其次采用WeakReference来关联观察者和主题。

            public void Register<TMessage>(object recipient, Action<TMessage> action)
            {
                lock (_registerLock)
                {
                    var messageType = typeof(TMessage);
    
                    Dictionary<Type, List<WeakAction>> recipients;
                   
                        if (_recipientsStrictAction == null)
                        {
                            _recipientsStrictAction = new Dictionary<Type, List<WeakAction>>();
                        }
    
                        recipients = _recipientsStrictAction;
    
                    lock (recipients)
                    {
                        List<WeakAction> list;
    
                        if (!recipients.ContainsKey(messageType))
                        {
                            list = new List<WeakAction>();
                            recipients.Add(messageType, list);
                        }
                        else
                        {
                            list = recipients[messageType];
                        }
    
                        var weakAction = new WeakAction<TMessage>(recipient, action);
                       
                        list.Add(weakAction);
                    }
                }
    
                RequestCleanup();
            }
    

    这个实现跟我们实现的EventBus大同小异,不同之处是dictionary类型为Dictionary<Type, List<WeakAction>>。

    WeakAction的构造函数:

            public WeakAction(object target, Action<T> action)
            {
    
                if (action.Method.IsStatic)
                {
                    _staticAction = action;
    
                    if (target != null)
                    {
                        Reference = new WeakReference(target);
                    }
    
                    return;
                }
    
    
                Method = action.Method;
                ActionReference = new WeakReference(action.Target);
                Reference = new WeakReference(target);
            }

    ActionReference = new WeakReference(action.Target); 这句话将一个object包装进了WeakReference。

    发送消息的代码也跟我们自己实现的EventBus大同小异,大家可以直接看代码对比。

    写一个测试看看如何使用Messenger:

            [Test]
            public void Should_handle_registered_actions()
            {
                int number = 0;
                Messenger.Default.Register<MessageA>(this,m=>number=m.Number);
                Messenger.Default.Send(new MessageA(2));
    
                number.Should().Be(2);
            }
    
            internal class MessageA
            {
                public MessageA(int number)
                {
                    Number = number;
                }
                public int Number { get; private set; }
            }

    我们注意到Messenger采用了消息的概念,所以发布主题也将方法名从publish改为了send。一般我们都说发布一个事件,发送一个消息。Messenger所提到的概念已经快要接近ServiceBus了。

  • 相关阅读:
    avaweb学习总结(八)——HttpServletResponse对象(二)
    javaweb学习总结(七)——HttpServletResponse对象(一)
    javaweb学习总结(六)——Servlet开发(二)
    javaweb学习总结(五)——Servlet开发(一)
    javaweb学习总结(四)——Http协议
    JAVAWeb学习总结(3)
    JAVAWeb学习总结(二)
    eclipse配置tomcat,访问http://localhost:8080出现404错误
    shader学习路线
    Unity3D WebCamTexture 调用外部摄像头
  • 原文地址:https://www.cnblogs.com/richieyang/p/4909397.html
Copyright © 2011-2022 走看看