EventAggregator, EventBus的实现
系列主题:基于消息的软件架构模型演变? .net中事件模型很优雅的实现了观察者模式,同时被大量的使用在各种框架中。如果我们非要给事件模型挑毛病,我觉得有两点:
于是我们想到了更加简单易用的模型:EventAggregator,正如该名称所描述,EventAggregator将观察者都聚合在一个容器里,向EventAggregator发布一个主题,EventAggregator会找到对该主题感兴趣的观察者并通知他。
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了。 (编辑:北几岛) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |

