基本思路:

(1)       在事件总线内部维护着一个事件与事件处理程序相映射的字典。

(2)       利用反射,事件总线会将实现了IEventHandler的处理程序与相应事件关联到一起,相当于实现了事件处理程序对事件的订阅。

(3)       当发布事件时,事件总线会从字典中找出相应的事件处理程序,然后利用反射去调用事件处理程序中的方法。

核心类(事件总线类)

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection; namespace Framework.EventBus
{
public class EventBus
{ private static EventBus _eventBus = null; private static Dictionary<Type, List<Type>> _eventMapping = new Dictionary<Type, List<Type>>(); // 在这个字典中,key存储的是事件,而value中存储的是事件处理程序 private EventBus() { }
/// <summary>
/// 单例
/// </summary>
/// <returns></returns>
public static EventBus Instance()
{
if (_eventBus == null)
{
_eventBus = new EventBus();
MapEvent2Handler();
}
return _eventBus;
} /// <summary>
/// 发布
/// 这里没有用到队列之类的东西,使用的是直接调用的方式
/// </summary>
/// <param name="eventData"></param>
public void Publish(BaseEvent eventData)
{
// 找出这个事件对应的处理者
Type eventType = eventData.GetType(); if (_eventMapping.ContainsKey(eventType) == true)
{
foreach (Type item in _eventMapping[eventType])
{
MethodInfo mi = item.GetMethod("Handle");
if (mi != null)
{
object o = Activator.CreateInstance(item);
mi.Invoke(o, new object[] { eventData });
}
} }
} /// <summary>
/// 将事件与事件处理程序映射到一起
/// 使用元数据来进行注册
/// </summary>
static void MapEvent2Handler()
{
Assembly assembly = Assembly.GetExecutingAssembly();
Type[] types = assembly.GetTypes(); foreach (Type type in types)
{
Type handlerInterfaceType = type.GetInterface("IEventHandler`1"); // 事件处理者 if (handlerInterfaceType != null) // 若是事件处理者,则以其泛型参数为key,事件处理者的集合为value添加到映射中
{
Type eventType = handlerInterfaceType.GetGenericArguments()[]; // 这里只有一个
// 查找是否存在key
if (_eventMapping.Keys.Contains(eventType))
{
List<Type> handlerTypes = _eventMapping[eventType];
handlerTypes.Add(type);
_eventMapping[eventType] = handlerTypes;
}
else // 存在则添加
{
List<Type> handlerTypes = new List<Type>();
handlerTypes.Add(type);
_eventMapping.Add(eventType, handlerTypes);
}
}
}
} }
}

 

核心类(事件基类)

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace Framework.EventBus
{
public class BaseEvent
{ /// <summary>
/// 事件发生的时间
/// </summary>
public DateTime EventTime { get; set; } /// <summary>
/// 事件源
/// </summary>
public object EventSource { get; set; } }
}

核心类(事件处理程序接口)

 namespace Framework.EventBus
{
public interface IEventHandler<T>
where T : BaseEvent
{
void Handle(T eventData);
}
}

使用方法

实现接口IEventHandler<T>

 using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace Framework.EventBus
{
/// <summary>
/// 实现了IEventHandler<OrderAddedEvent>接口,就是订阅了OrderAddedEvent事件
/// </summary>
public class OrderAddedEventHandler1 : IEventHandler<OrderAddedEvent>
{
public void Handle(OrderAddedEvent eventData)
{ Console.WriteLine("\r\n");
Console.WriteLine("订单的数据是:" );
Console.WriteLine(" 订单号:" + eventData.Order.OrderId);
Console.WriteLine(" 订单金额:" + eventData.Order.OrderAmount);
Console.WriteLine(" 下单时间:" + eventData.Order.OrderDateTime); }
}
}

注:实现了IEventHandler<OrderAddedEvent>接口,就是订阅了OrderAddedEvent事件

订单类

 public class OrderEntity
{ /// <summary>
/// 订单编号
/// </summary>
public string OrderId { get; set; } /// <summary>
/// 下单日期
/// </summary>
public DateTime OrderDateTime { get; set; } /// <summary>
/// 订单金额
/// </summary>
public decimal OrderAmount { get; set; } }

发布事件

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace Framework.EventBus
{
class Program
{
static void Main(string[] args)
{
EventBus bus = EventBus.Instance(); OrderEntity order = new OrderEntity() { OrderId = "", OrderDateTime = DateTime.Now, OrderAmount = };
bus.Publish(new OrderAddedEvent() { EventTime = DateTime.Now, Order = order }); // 发布OrderAddedEvent事件, Console.Read();
} }
}

 运行结果

改进

(1)实现基于msmq的事件总线,使得系统能够进行分布式的事件订阅和发布。

下载

示例代码

参考资料

aspnetboilerplate

https://github.com/aspnetboilerplate/aspnetboilerplate

分享一个分布式消息总线,基于.NET Socket Tcp的发布-订阅框架

http://www.cxyclub.cn/n/53667/

Guava - EventBus(事件总线)

http://greengerong.com/blog/2014/11/27/guava-eventbus/

DDD~领域事件与事件总线

http://www.cnblogs.com/lori/p/3476703.html

事件总线 EventBus的设计

http://www.cnblogs.com/MartinChen999/archive/2011/12/21/2294034.html

DDD事件总线的实现的更多相关文章

  1. DDD事件总线

    DDD事件总线 基本思路: (1)       在事件总线内部维护着一个事件与事件处理程序相映射的字典. (2)       利用反射,事件总线会将实现了IEventHandler的处理程序与相应事件 ...

  2. 事件总线(Event Bus)知多少

    源码路径:Github-EventBus 简书同步链接 1. 引言 事件总线这个概念对你来说可能很陌生,但提到观察者(发布-订阅)模式,你也许就很熟悉.事件总线是对发布-订阅模式的一种实现.它是一种集 ...

  3. ABP之事件总线(3)

    承接上一篇时间总线的学习,在上一篇中我们实现了取消显式注册事件的方式,采用使用反射的方式.这样的好处可以解除Publisher和Scriber的显式依赖,但是问题又来了,因为我们只有Publisher ...

  4. Autofac解耦事件总线

    事件总线之Autofac解耦 事件总线是通过一个中间服务,剥离了常规事件的发布与订阅(消费)强依赖关系的一种技术实现.事件总线的基础知识可参考圣杰的博客[事件总线知多少] 本片博客不再详细概述事件总线 ...

  5. 事件总线(Event Bus)

    事件总线(Event Bus)知多少 源码路径:Github-EventBus简书同步链接 1. 引言 事件总线这个概念对你来说可能很陌生,但提到观察者(发布-订阅)模式,你也许就很熟悉.事件总线是对 ...

  6. Lind.DDD.Events事件总线~自动化注册

    回到目录 让大叔兴奋的自动化注册 对于领域事件之前说过,在程序启动时订阅(注册)一些事件处理程序,然后在程序的具体位置去发布(触发)它,这是传统的pub/sub模式的体现,当然也没有什么问题,为了让它 ...

  7. DDD~领域事件与事件总线

    回到目录 谈谈它 终于有些眉目了,搜刮了很多牛人的资料,英文的,中文的,民国文的,终于小有成就了,同时也做了个DEMO,领域事件这东西好,但需要你明白它之后才会说好,而对于明白领域事件这件事来说,它的 ...

  8. Guava - EventBus(事件总线)

    Guava在guava-libraries中为我们提供了事件总线EventBus库,它是事件发布订阅模式的实现,让我们能在领域驱动设计(DDD)中以事件的弱引用本质对我们的模块和领域边界很好的解耦设计 ...

  9. EventBus(事件总线)

    EventBus(事件总线) Guava在guava-libraries中为我们提供了事件总线EventBus库,它是事件发布订阅模式的实现,让我们能在领域驱动设计(DDD)中以事件的弱引用本质对我们 ...

随机推荐

  1. MUI上传图片之选择相册和相机上传

    1.因为项目中有三处地方需要上传,所以html中存在三处地方.身份证正反面为上传一张,发票限制上传9张. <div class="action1"> <!--展示 ...

  2. struts2-第一章-基础用法2

    一,回顾 struts2框架搭建步骤 (1)创建maven项目 (2)web.xml配置struts2的核心过滤器(filter) (3)pom.xml配置servlet,struts的依赖 (4)把 ...

  3. js 如何将dom转换为 图片(base64)

    1.引入js <script src="https://cdn.bootcss.com/html2canvas/0.4.1/html2canvas.js"></s ...

  4. Make a plan

    1. 思考 2. 学习英语 3. 练习书法 执行周期:2015年1月15日到2016年1月16日. 要像每一次用餐一样对待每一天的计划. 早晨起来,第一件事情是洗漱,然后是思考: 中午时间,第一件事情 ...

  5. Angular changeDetction

    ChangeDection 检测程序内部状态,然后反映到UI上. 引起状态变化:Events,XHR,Timers ApplicationRef监听NgZone的onTurnDone,然后执行检测. ...

  6. 使用Linux命令行测试网速

    安装speedtest speedtest是一个用Python编写的轻量级Linux命令行工具,在Python2.4至3.4版本下均可运行.它基于Speedtest.net的基础架构来测量网络的上/下 ...

  7. css边框动画

    <div class="button">hover me to change</div> .button{ width:200px; height:60px ...

  8. UOJ#291. 【ZJOI2017】树状数组 树套树

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ291.html 题解 结论:这个写错的树状数组支持的是后缀加和后缀求和.这里的后缀求和在 x = 0 的时 ...

  9. SQL增删改语句

    一,插入数据 1.使用  insert ...values 语句插入单行或多行元组数据 insert  into 表名 (列名,列名,...,列名) values 值 表名:指被插入数据的表名 列名: ...

  10. maya cmds pymel 'ESC' 退出 while, for 循环

    maya cmds pymel 'ESC' 退出 while, for 循环 import maya.cmds as cmds cmds.progressWindow(isInterruptable= ...