在C#中,我们可以在一个类中定义自己的事件,而其他的类可以订阅该事件,当某些事情发生时,可以通知到该类。这对于桌面应用或者独立的windows服务来说是非常有用的。但对于一个web应用来说是有点问题的,因为对象都是在web请求中创建的,而且这些对象生命周期都很短,因而注册某些类的事件是很困难的。此外,注册其他类的事件会使得类紧耦合。事件总线便可以用来解耦并重复利用应用中的逻辑。

事件总线带来的好处和引入的问题

好处比较明显,就是独立出一个发布订阅模块,调用者可以通过使用这个模块,屏蔽一些线程切换问题,简单地实现发布订阅功能。

坏处可能比较隐晦,但这些需要足够引起我们的重视

  • 大量的滥用,将导致逻辑的分散,出现问题后很难定位。
  • 没办法实现强类型,在编译的时候就发现问题。
  • 代码可读性有些问题,IDE无法识别这些协议,对IDE不友好。
总得来说,如果项目里面有大量的事件交互,那么还是可以通过EventBus来实现,否则还是推荐自己在模块内部实现观察者模式。
 

示例代码

所以今天介绍一个简单的事件总线,它是事件发布订阅模式的实现,让我们能在领域驱动设计(DDD)中以事件的弱引用本质对我们的模块和领域边界很好的解耦设计。

目前,所有的源代码已经提交到github 上,地址:https://github.com/weizhong1988/Weiz.EventBus

程序目录结构如下:

事件总线

事件总线是被所有触发并处理事件的其他类共享的单例对象。要使用事件总线,首先应该获得它的一个引用。下面有两种方法来处理:

订阅事件

触发事件之前,应该先要定义该事件。EventBus为我们提供了Subscribe 方法来订阅事件:

        public void Subscribe<TEvent>(IEventHandler<TEvent> eventHandler) where TEvent : IEvent
{
//同步锁
lock (_syncObject)
{
//获取领域模型的类型
var eventType = typeof(TEvent);
//如果此领域类型在事件总线中已注册过
if (_dicEventHandler.ContainsKey(eventType))
{
var handlers = _dicEventHandler[eventType];
if (handlers != null)
{
handlers.Add(eventHandler);
}
else
{
handlers = new List<object>
{
eventHandler
};
}
}
else
{
_dicEventHandler.Add(eventType, new List<object> { eventHandler });
}
}
}

所以的事件都集成自IEvent,该类包含了类处理事件需要的属性。

 var sendEmailHandler = new UserAddedEventHandlerSendEmail();
var sendMessageHandler = new UserAddedEventHandlerSendMessage();
var sendRedbagsHandler = new UserAddedEventHandlerSendRedbags();
Weiz.EventBus.Core.EventBus.Instance.Subscribe(sendEmailHandler);
Weiz.EventBus.Core.EventBus.Instance.Subscribe(sendMessageHandler);
//Weiz.EventBus.Core.EventBus.Instance.Subscribe<UserGeneratorEvent>(sendRedbagsHandler);
Weiz.EventBus.Core.EventBus.Instance.Subscribe<OrderGeneratorEvent>(sendRedbagsHandler);

发布事件

对于事件源,则可以通过Publish 方法发布事件。触发一个事件很简单,如下所示:

     public void Publish<TEvent>(TEvent tEvent, Action<TEvent, bool, Exception> callback) where TEvent : IEvent
{
var eventType = typeof(TEvent);
if (_dicEventHandler.ContainsKey(eventType) && _dicEventHandler[eventType] != null &&
_dicEventHandler[eventType].Count > )
{
var handlers = _dicEventHandler[eventType];
try
{
foreach (var handler in handlers)
{
var eventHandler = handler as IEventHandler<TEvent>;
eventHandler.Handle(tEvent);
callback(tEvent, true, null);
}
}
catch (Exception ex)
{
callback(tEvent, false, ex);
}
}
else
{
callback(tEvent, false, null);
}
}

下面是发布事件的调用:

            var orderGeneratorEvent = new OrderGeneratorEvent { OrderId = Guid.NewGuid() };

            System.Console.WriteLine("{0}下单成功", orderGeneratorEvent.OrderId);

            Weiz.EventBus.Core.EventBus.Instance.Publish(orderGeneratorEvent, CallBack);

定义处理事件

要处理一个事件,应该要实现IEventHandler接口,如下所示:

    /// <summary>
/// send email
/// </summary>
public class UserAddedEventHandlerSendEmail : IEventHandler<UserGeneratorEvent>
{ public void Handle(UserGeneratorEvent tEvent)
{
System.Console.WriteLine(string.Format("{0}的邮件已发送", tEvent.UserId));
}
}

处理多事件

在一个单一的处理句柄中,可以处理多个事件。这时,你应该为每个事件实现IEventHandler。比如:

    /// <summary>
/// red bags.
/// </summary>
public class UserAddedEventHandlerSendRedbags : IEventHandler<UserGeneratorEvent>,IEventHandler<OrderGeneratorEvent>
{
public void Handle(OrderGeneratorEvent tEvent)
{
System.Console.WriteLine(string.Format("{0}的下单红包已发送", tEvent.OrderId));
} public void Handle(UserGeneratorEvent tEvent)
{
System.Console.WriteLine(string.Format("{0}的注册红包已发送", tEvent.UserId));
}
}

最后

以上,就把事件总线介绍完了,完整的代码,请到github 上下载,这个只是EventBus 的简单实现,各位可以根据自己的实际场景和需求,优化修改。

C#总结(六)EventBus事件总线的使用-自己实现事件总线的更多相关文章

  1. 从零开始学 Web 之 DOM(六)为元素绑定与解绑事件

    大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... +-------------------------------------------------------- ...

  2. 从零开始学 Web 之 jQuery(六)为元素绑定多个相同事件,解绑事件

    大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...

  3. 第一百六十九节,jQuery,基础事件

    jQuery,基础事件 学习要点: 1.绑定事件 2.简写事件 3.复合事件 JavaScript 有一个非常重要的功能,就是事件驱动.当页面完全加载后,用户通过鼠标 或键盘触发页面中绑定事件的元素即 ...

  4. Javascript事件模型系列(一)事件及事件的三种模型

    一.开篇 在学习javascript之初,就在网上看过不少介绍javascript事件的文章,毕竟是js基础中的基础,文章零零散散有不少,但遗憾的是没有看到比较全面的系列文章.犹记得去年这个时候,参加 ...

  5. JAVA之旅(三十一)——JAVA的图形化界面,GUI布局,Frame,GUI事件监听机制,Action事件,鼠标事件

    JAVA之旅(三十一)--JAVA的图形化界面,GUI布局,Frame,GUI事件监听机制,Action事件,鼠标事件 有段时间没有更新JAVA了,我们今天来说一下JAVA中的图形化界面,也就是GUI ...

  6. javaScript事件(九)事件类型之触摸与手势事件

    一.触摸事件 touchstart:当手指触摸屏幕时触发:即使已经有一个手指放在了屏幕上也会触发. touchmove:当手指在屏幕上滑动时连续地触发.在这个世界发生期间,调用preventDefau ...

  7. javascript中事件总结&通用的事件侦听器函数封装&事件委托

    前言: JAVASCRIPT与HTML之间的交互是通过事件来实现的.事件,就是文档或浏览器窗口中发生的一些特定交互瞬间.可以使用侦听器( 或处理程序 )来预定事件,以便事件发生时执行相应的代码.这种在 ...

  8. 深入理解DOM事件机制系列第四篇——事件模拟

    × 目录 [1]引入 [2]模拟机制 [3]自定义事件 前面的话 事件是网页中某个特别的瞬间,经常由用户操作或通过其他浏览器功能来触发.但实际上,也可以使用javascript在任意时刻来触发特定的事 ...

  9. 深入理解DOM事件类型系列第一篇——鼠标事件

    × 目录 [1]类型 [2]顺序 [3]坐标位置[4]修改键[5]相关元素[6]鼠标按键[7]滚轮事件[8]移动设备 前面的话 鼠标事件是web开发中最常用的一类事件,毕竟鼠标是最主要的定位设备.本文 ...

随机推荐

  1. Centos7新功能

    Centos7 单用户模式   centos7里不再有0-6启动级别,而是4个target   graphical.target  多人模式,支持图形和命令行两种登录,对应之前的3,5级别   mul ...

  2. 奥酷HTML5视频直播系统AMS6.0

    今日,北极星通自主研发的流媒体服务系统Aoku Media Server6.0发布了,将正式支持HTML5直播,这使得网页中无需有flash播放插件或者其他插件,可直接观看直播,HTML5直播也会使得 ...

  3. 有关datatables的非常规教程

    有关datatables的非常规教程 1. //$.fn.dataTable.tables({ visible: true, api: true }).columns.adjust(); table. ...

  4. JDBC 基础

    JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口 ...

  5. Android Stdio 中的Rendering Problems Android N requires the IDE to be running with Java 1.8 or later Install a supported JDK解决办法

    出现如下图所示的错误 解决办法为: 然后在里面输入SDK 下载 下载APILevel为23版本的SDK 换成23版本的SDK 完美解决问题

  6. Java多线程推荐使用的停止方法和暂停方法

    判断线程结束和让线程结束 package cn.lonecloud.Thread.study; /** * 用于循环1000次的线程 * @Title: Run1000Thread.java * @P ...

  7. Elasticsearch教程-从入门到精通(转载)

    转载,原文地址:http://mageedu.blog.51cto.com/4265610/1714522?utm_source=tuicool&utm_medium=referral 各位运 ...

  8. java2 - 语言基础

    一.结构流程图制作工具 xmind 的使用 二.Java 基础数据类型 回答以下问题: java 基本数据类型有几种? 整数类型是哪几种? 浮点数类型是哪几种? 字符类型关键字? 布尔类型关键字? 为 ...

  9. 初识Vue——模板语法

    一.插值 1.文本 数据绑定最常见的形式是使用双大括号({{  }}--"Mustache"语法)的文本插值 <div class="mustache"& ...

  10. CentOs环境下给PHP7.0安装fileinfo扩展

    由于项目搭建处于一个初步阶段,由于环境的不成熟出现过一系列的问题是难免的,在关于文件操作的程序中,报出一个缺少扩展的错误,已经解决~ 看一下官方给出的说明,http://php.net/manual/ ...