DDD事件总线

基本思路:

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

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

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

核心类(事件总线类)

 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Reflection;
5
6
7 namespace Framework.EventBus
8 {
9 public class EventBus
10 {
11
12 private static EventBus _eventBus = null;
13
14 private static Dictionary<Type, List<Type>> _eventMapping = new Dictionary<Type, List<Type>>(); // 在这个字典中,key存储的是事件,而value中存储的是事件处理程序
15
16
17 private EventBus() { }
18 /// <summary>
19 /// 单例
20 /// </summary>
21 /// <returns></returns>
22 public static EventBus Instance()
23 {
24 if (_eventBus == null)
25 {
26 _eventBus = new EventBus();
27 MapEvent2Handler();
28 }
29 return _eventBus;
30 }
31
32
33
34 /// <summary>
35 /// 发布
36 /// 这里没有用到队列之类的东西,使用的是直接调用的方式
37 /// </summary>
38 /// <param name="eventData"></param>
39 public void Publish(BaseEvent eventData)
40 {
41 // 找出这个事件对应的处理者
42 Type eventType = eventData.GetType();
43
44 if (_eventMapping.ContainsKey(eventType) == true)
45 {
46 foreach (Type item in _eventMapping[eventType])
47 {
48 MethodInfo mi = item.GetMethod("Handle");
49 if (mi != null)
50 {
51 object o = Activator.CreateInstance(item);
52 mi.Invoke(o, new object[] { eventData });
53 }
54 }
55
56 }
57 }
58
59
60
61
62
63 /// <summary>
64 /// 将事件与事件处理程序映射到一起
65 /// 使用元数据来进行注册
66 /// </summary>
67 static void MapEvent2Handler()
68 {
69 Assembly assembly = Assembly.GetExecutingAssembly();
70 Type[] types = assembly.GetTypes();
71
72 foreach (Type type in types)
73 {
74 Type handlerInterfaceType = type.GetInterface("IEventHandler`1"); // 事件处理者
75
76 if (handlerInterfaceType != null) // 若是事件处理者,则以其泛型参数为key,事件处理者的集合为value添加到映射中
77 {
78 Type eventType = handlerInterfaceType.GetGenericArguments()[0]; // 这里只有一个
79 // 查找是否存在key
80 if (_eventMapping.Keys.Contains(eventType))
81 {
82 List<Type> handlerTypes = _eventMapping[eventType];
83 handlerTypes.Add(type);
84 _eventMapping[eventType] = handlerTypes;
85 }
86 else // 存在则添加
87 {
88 List<Type> handlerTypes = new List<Type>();
89 handlerTypes.Add(type);
90 _eventMapping.Add(eventType, handlerTypes);
91 }
92 }
93 }
94 }
95
96 }
97 }

 

核心类(事件基类)

 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 namespace Framework.EventBus
7 {
8 public class BaseEvent
9 {
10
11 /// <summary>
12 /// 事件发生的时间
13 /// </summary>
14 public DateTime EventTime { get; set; }
15
16 /// <summary>
17 /// 事件源
18 /// </summary>
19 public object EventSource { get; set; }
20
21
22 }
23 }

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

1 namespace Framework.EventBus
2 {
3 public interface IEventHandler<T>
4 where T : BaseEvent
5 {
6 void Handle(T eventData);
7 }
8 }

使用方法

实现接口IEventHandler<T>

 1 using System;
2 using System;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Text;
6
7
8 namespace Framework.EventBus
9 {
10 /// <summary>
11 /// 实现了IEventHandler<OrderAddedEvent>接口,就是订阅了OrderAddedEvent事件
12 /// </summary>
13 public class OrderAddedEventHandler1 : IEventHandler<OrderAddedEvent>
14 {
15 public void Handle(OrderAddedEvent eventData)
16 {
17
18 Console.WriteLine("\r\n");
19 Console.WriteLine("订单的数据是:" );
20 Console.WriteLine(" 订单号:" + eventData.Order.OrderId);
21 Console.WriteLine(" 订单金额:" + eventData.Order.OrderAmount);
22 Console.WriteLine(" 下单时间:" + eventData.Order.OrderDateTime);
23
24 }
25 }
26 }

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

订单类

 1 public class OrderEntity
2 {
3
4 /// <summary>
5 /// 订单编号
6 /// </summary>
7 public string OrderId { get; set; }
8
9
10 /// <summary>
11 /// 下单日期
12 /// </summary>
13 public DateTime OrderDateTime { get; set; }
14
15
16 /// <summary>
17 /// 订单金额
18 /// </summary>
19 public decimal OrderAmount { get; set; }
20
21 }

发布事件

 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6
7 namespace Framework.EventBus
8 {
9 class Program
10 {
11 static void Main(string[] args)
12 {
13 EventBus bus = EventBus.Instance();
14
15 OrderEntity order = new OrderEntity() { OrderId = "20151017001", OrderDateTime = DateTime.Now, OrderAmount = 500 };
16 bus.Publish(new OrderAddedEvent() { EventTime = DateTime.Now, Order = order }); // 发布OrderAddedEvent事件,
17
19 Console.Read();
20 }
21
22 }
23 }

 运行结果

改进

(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事件总线的实现

    基本思路: (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. 从PCI上读取数据 线程和定时器效率

    从PCI上读取数据 线程和定时器效率 线程: mythread=AfxBeginThread(StartContinuous,(LPVOID)1,THREAD_PRIORITY_NORMAL,0,CR ...

  2. 完全合并C++面试题

    C++面试题 1.是不是父母写了virtual 功能,假设子类重写它的功能不virtual ,也使多态性? virtual修饰符隐形遗传. private 还集成.问权限而已 virtual可加可不加 ...

  3. C#里System.Data.SQLite中对GUID的处理

    string sqlstring = "select * from endpoint_policy where HEX([UserGuid]) ='" + CommonHelper ...

  4. Android自己定义组件系列【5】——高级实践(1)

    在接下来的几篇文章将任老师的博文<您可以下拉PinnedHeaderExpandableListView实现>骤来具体实现.来学习一下大神的代码并记录一下. 原文出处:http://blo ...

  5. .net机试题总结

    1.下面是一个由*号组成的4行倒三角形图案.要求:1.输入倒三角形的行数,行数的取值3-21之间,对于非法的行数,要求抛出提示“非法行数!”:2.在屏幕上打印这个指定了行数的倒三角形. ******* ...

  6. 在mac os下编译android -相关文章

    1. Mac OS X下编译Android源码 http://blog.csdn.net/bulreed/article/details/22783467 2.MAC OS 编译 Android源代码 ...

  7. 在 树莓派上使用 c++ libsockets library

    rpi默认安装的编译器是gcc-4.6.2 而现在最新的c++ libsockets library 需要使用支持c++-11特征的编译器,即需要4.8.2才可以.为此,需要先升级编译器才可以支持编译 ...

  8. WPF中两条路径渐变的探讨

    原文:WPF中两条路径渐变的探讨 我们在WPF中,偶尔也会涉及到两条路径作一些“路径渐变 ”.先看看比较简单的情形:如下图(关键点用红色圆点加以标识):(图1) 上面图1中的第1幅图可以说是最简单的路 ...

  9. Hadoop学习笔记Hadoop伪分布式环境建设

    建立一个伪分布式Hadoop周围环境 1.主办(Windows)顾客(安装在虚拟机Linux)网络连接. a) Host-only 主机和独立客户端联网: 好处:网络隔离: 坏处:虚拟机和其他serv ...

  10. Twitter实时搜索系统EarlyBird

    twitter要存档tweet采用lucene做全量指数,新发型是实时索引推文.检索实时(10在几秒钟内指数).实时索引和检索系统,称为EarlyBird. 感觉写更清晰,简洁,这个信息是真实的,只有 ...