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

.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了。

EventAggregator, EventBus的实现的更多相关文章

  1. Core 1.0中的管道-中间件模式

    ASP.NET Core 1.0中的管道-中间件模式 SP.NET Core 1.0借鉴了Katana项目的管道设计(Pipeline).日志记录.用户认证.MVC等模块都以中间件(Middlewar ...

  2. 事件总线 EventBus

    661. .net中事件模型很优雅的实现了观察者模式,同时被大量的使用在各种框架中. [2016-04-30 10:52:42]662. Prism框架中实现了一个典型的EventAggregator ...

  3. Android消息传递之基于RxJava实现一个EventBus - RxBus

    前言: 上篇文章学习了Android事件总线管理开源框架EventBus,EventBus的出现大大降低了开发成本以及开发难度,今天我们就利用目前大红大紫的RxJava来实现一下类似EventBus事 ...

  4. EventBus实现activity跟fragment交互数据

    最近老是听到技术群里面有人提出需求,activity跟fragment交互数据,或者从一个activity跳转到另外一个activity的fragment,所以我给大家介绍一个开源项目,EventBu ...

  5. 【热门技术】EventBus 3.0,让事件订阅更简单,从此告别组件消息传递烦恼~

    一.写在前面 还在为时间接收而烦恼吗?还在为各种组件间的消息传递烦恼吗?EventBus 3.0,专注于android的发布.订阅事件总线,让各组件间的消息传递更简单!完美替代Intent,Handl ...

  6. 快速Android开发系列通信篇之EventBus

    先吐槽一下博客园的MarkDown编辑器,推出的时候还很高兴博客园支持MarkDown了,试用了下发现支持不完善就没用了,这次这篇是在其他编辑器下写的,复制过来后发现..太烂了.怎么着作为一个技术博客 ...

  7. ABP源码分析二十五:EventBus

    IEventData/EventData: 封装了EventData信息,触发event的源对象和时间 IEventBus/EventBus: 定义和实现了了一系列注册,注销和触发事件处理函数的方法. ...

  8. ABP框架 - 领域事件(EventBus)

    文档目录 本节内容: EventBus 注入 IEventBus 获取默认实例 定义事件 预定义事件 处理完异常 实体修改 触发事件 处理事件 处理基类事件 处理程序异常 处理多个事件 处理程序注册 ...

  9. Android开发学习之路-EventBus使用

    EventBus是一个通过发布.订阅事件实现组件间消息传递的工具. 它存在的目的,就是为了优化组件之间传递消息的过程.传统组件之间传递消息的方法有使用广播,回调等,而这些方法使用都比较复杂. 工作原理 ...

随机推荐

  1. APP产品交互设计分析总结(不断更新中...)

    1.首页中的最下方的TAB和中部的TAB的区别 最下面的tab按钮应该是核心级模块级的大功能入口 中间的按钮应该是次核心级页面级的小功能入口 2.对于编辑是在单页内实现好还是跳转到新页面实现好 内容比 ...

  2. 安装Kafka

    1.默认安装好zookeeper和scala2.下载安装包,解压 tar -zxvf kafka_2.11-0.9.0.1.tgz kafka_2.11-0.9.0.13.配置环境变量 vim /et ...

  3. 进击的Python【第七章】:Python的高级应用(四)面向对象编程进阶

    Python的高级应用(三)面向对象编程进阶 本章学习要点: 面向对象高级语法部分 静态方法.类方法.属性方法 类的特殊方法 反射 异常处理 Socket开发基础 一.面向对象高级语法部分 静态方法 ...

  4. SGIP、SMGP 长短信发送问题小结

    长短信发送问题.1.将信息长度拆开发送.2.为了解决长短信拆分发送,在手机终端,收到的顺序错乱,所以在每一段短信发送完成后,延时5秒,这样在手机终端客户收到的信息,就会按照拆分的顺序发送. //信息总 ...

  5. jquery轮播图详解,40行代码即可简单解决。

    我在两个月以前没有接触过html,css,jquery,javascript.今天我却在这里分享一篇技术贴,可能在技术大牛面前我的文章漏洞百出,也请斧正. 可以看出来,无论是div+css布局还是jq ...

  6. 好文分享_java堆栈的区别

    Java Heap Memory Heap memory is used by java runtime to allocate memory to Objects and JRE classes. ...

  7. java-并发-同步

    浏览以下内容前,请点击并阅读 声明 线程间的通信主要是通过访问以及对象引用字段,这种形式的通信非常高效,但是会产生两种可能的错误:线程干扰和内存一致性错误,反正这些错误的工具就是同步. 然而,同步可能 ...

  8. jQuery 遍历函数

    转载http://www.cnblogs.com/tylerdonet/archive/2013/04/05/3000618.html jQuery 遍历函数包括了用于筛选.查找和串联元素的方法. 函 ...

  9. LeetCode刷刷记录

    一遍考研,一遍还是要刷刷题.感觉自己的时间安排的不是很好,还是要抓紧自己的日常时间,当然,也要练练刷题的手感. 1.第一题就两重循环找到索引就OK,因为是无序的,所以就不能用二分来查找,题目中每个数的 ...

  10. 【SAP BO】处理掉BOE打开Xcelsius报表时,外围出现的外边框(转)

    原帖地址:http://blog.csdn.net/liyi199488/article/details/8943286 通过BOE打开Xcelsius报表时,总是出现一个外边框. 处理办法: Xce ...