EventBus 事件总线模式实例(发布/订阅事件)
在我们公司经常用到总线,具体的总线是什么让我理解我也不清楚,但是在这几个月下来,我已经知道总线如何使用,现在加上示例讲解总线如何使用。
1. 首先我们的新建一个类,这个类其实是用于总线传递的模型
using System;
namespace PurchaseDevices.Model.CommonModel
{
/// <summary>
/// 事件传递参数
/// </summary>
/// <typeparam name="T"></typeparam>
public class FlowDataEventArgs<T> : EventArgs
{
public FlowDataEventArgs(T data)
{
Data = data;
}
public T Data { get; set; }
}
}
2. 建立一个类(FlowServiceBus),里面来写总线的方法。
public class FlowServiceBus
{
static FlowServiceBus _flowServiceBus;
public static FlowServiceBus Instance
{
get
{
if (_flowServiceBus == null) _flowServiceBus = new FlowServiceBus();
return _flowServiceBus;
}
}
}
4. 写一个方法,里面挂总线
public class FlowServiceBus
{
static FlowServiceBus _flowServiceBus;
public static FlowServiceBus Instance
{
get
{
if (_flowServiceBus == null) _flowServiceBus = new FlowServiceBus();
return _flowServiceBus;
}
}
public void ConfigMsgDispachRule(){
//挂总线
}
}
5. 先讲一讲我们传统的调用另一个类的方法
//新建一个对象模型类
public class FarmerCardOrRateSellModel
{
public FarmerCardOrRateSellModel()
{
PackageHead = 0xAA;
FixedLength = 11;
}
/// <summary>
/// 帧头
/// 帧开始标记,0xAA
/// </summary>
public byte PackageHead { get; set; }
/// <summary>
/// 接收者,标识数据要发给谁
/// 1磅码主机、2定级键盘、3交烟刷卡。
/// </summary>
public byte Receiver { get; set; }
/// <summary>
/// 发送者,标识数据是谁发出
/// 1磅码主机、2定级键盘、3交烟刷卡。
/// </summary>
public byte Sender { get; set; }
/// <summary>
/// Zigbee通信地址
/// 1~15
/// </summary>
public byte ZigbeeAddress { get; set; }
/// <summary>
/// 帧序号
/// 0~255
/// </summary>
public byte FrameNumber { get; set; }
/// <summary>
/// 命令码
/// </summary>
public byte Command { get; set; }
/// <summary>
/// 数据区字节数
///
/// </summary>
public int DataLength { get; set; }
/// <summary>
/// 数据区,可无(数据区为0)
/// </summary>
public byte[] Data { get; set; }
/// <summary>
/// 从receiver到整个data的和校验
/// </summary>
public byte Crc { get; set; }
/// <summary>
/// 定长 除开数据区的长度 定长为11
/// </summary>
public int FixedLength { get; set; }
}
//我们现在要做的是 根据不同的发送者Sender ,进入不同的方法
private void DisSenderToDisWay(FarmerCardOrRateSellModel farmerCardOrRateSellModel)
{
DevTypeEnum devTypeEnum = (DevTypeEnum)farmerCardOrRateSellModel.Sender; //这里是一个枚举,这里就不详细讲解了,这里就是说 //Sender有不同的值
switch (devTypeEnum)
{
case DevTypeEnum.CardDev:
CardDev cardDev=new CardDev ();
cardDev.CardDevWay(farmerCardOrRateSellModel);
break;
case DevTypeEnum.LevelDev:
LevelDev levelDev=new LevelDev();
levelDev.LevelDevWay(farmerCardOrRateSellModel);
break;
default:
Logger.GetInstance().Warn("无法识别的发送者");
break;
}
}
//当sender为CardDev要执行的方法
public class CardDev{
public void CardDevWay(FarmerCardOrRateSellModel farmerCardOrRateSellModel){
//执行的方法
}
}
//当sender为LevelDev要执行的方法
public class LevelDev{
public void LevelDevWay(FarmerCardOrRateSellModel farmerCardOrRateSellModel){
//执行的方法
}
}
}
在传统的方法中 ,一个类要引用另一个类的方法,我们必须new 一个对象,然后引用方法。这样写没有错,我以前也是这样写的,对于一些不复杂程序中的我么可以这样写,但是在一些与设备交互的程序中,多半是总线将各个方法连接起来,我们不必关心谁是发送者,谁是接收者,每个方法只关心我拿到这个传递过来的值,该干什么,我也不必关心我应该把这个方法的结果发给谁用。这样低耦合。
现在我们来讲讲用总线的方法,应该怎么写:
还是保留FarmerCardOrRateSellModel类。
下面这个方法 我们用事件来写:
写事件:
public event EventHandler<FlowDataEventArgs<FarmerCardOrRateSellModel>> OnReceiveCardDataEventHadler;
public event EventHandler<FlowDataEventArgs<FarmerCardOrRateSellModel>> OnReceiveLevelDataEventHadler;
private void DisSenderToDisWay(FarmerCardOrRateSellModel farmerCardOrRateSellModel)
{
DevTypeEnum devTypeEnum = (DevTypeEnum)farmerCardOrRateSellModel.Sender;
switch (devTypeEnum)
{
case DevTypeEnum.CardDev:
if (OnReceiveCardDataEventHadler!=null)
{
OnReceiveCardDataEventHadler(this,new FlowDataEventArgs<FarmerCardOrRateSellModel>(farmerCardOrRateSellModel));
}
break;
case DevTypeEnum.LevelDev:
if (OnReceiveLevelDataEventHadler!=null)
{
OnReceiveLevelDataEventHadler(this, new FlowDataEventArgs<FarmerCardOrRateSellModel>(farmerCardOrRateSellModel));
}
break;
default:
Logger.GetInstance().Warn("无法识别的发送者");
break;
}
}
//我们要写两个方法 ,这两个方法就是Sender为LevelDev 和CardDev,他们拿到数据自己需要怎么处理的方法了
//当sender为CardDev要执行的方法
public class CardDev{
public void CardDevWay(object sender, FlowDataEventArgs<FarmerCardOrRateSellModel> e){
var data=e.Data; //data就为传送过来的FarmerCardOrRateSellModel对象
}
}
//当sender为LevelDev 要执行的方法
public class LevelDev{
public void LevelDevWay(object sender, FlowDataEventArgs<FarmerCardOrRateSellModel> e){
var data=e.Data; //data就为传送过来的FarmerCardOrRateSellModel对象
}
}
//写到这里 我们已经把各自内部的方法完成了,现在我们要完成的就是 ,如何将方法与方法直接串联起来,怎么让sender为CardDev时就进入对应的CardDevWay方法南。那么现在就是要挂总线了。
还记的我们在总线类里面写的方法么:
现在我们要在里面添加一些代码了。
public class FlowServiceBus
{
static FlowServiceBus _flowServiceBus;
public static FlowServiceBus Instance
{
get
{
if (_flowServiceBus == null) _flowServiceBus = new FlowServiceBus();
return _flowServiceBus;
}
}
//新建对象
private readonly DisSenderToDisWay _disSenderToDisWay=new DisSenderToDisWay();
private readonly CardDev _cardDev=new CardDev ();
private readonly LevelDev _levelDev=new LevelDev ();
public void ConfigMsgDispachRule(){
EventBroker eventBroker =new EventBroker();
eventBroker.SpecialCasesRegistrar.AddPublication("发送者为CardDev 的方法", _disSenderToDisWay,
"OnReceiveCardDataEventHadler", HandlerRestriction.None);
eventBroker.SpecialCasesRegistrar.AddSubscription<FlowDataEventArgs<FarmerCardOrRateSellModel>>("发送者为CardDev 的方法",
_cardDev, _cardDev.CardDevWay, new OnPublisher());
//这是一组对应的 可以这样理解 :当执行到DisSenderToDisWay 类里面的OnReceiveCardDataEventHadler事件时,就执行CardDev 里面的CardDevWay方法
//按照以上的里面 当我们执行DisSenderToDisWay 类里面的OnReceiveLevelDataEventHadler事件时,接下来我们应该执行LevelDev类里面的LevelDevWay方法南
eventBroker.SpecialCasesRegistrar.AddPublication("发送者为LevelDev 的方法", _disSenderToDisWay,
"OnReceiveLevelDataEventHadler", HandlerRestriction.None);
eventBroker.SpecialCasesRegistrar.AddSubscription<FlowDataEventArgs<FarmerCardOrRateSellModel>>("发送者为LevelDev 的方法",
_levelDev, _levelDev.LevelDevWay, new OnPublisher());
}
}
总线这个要慢慢理解,刚开始我也不知道如何将两个方法挂接起来的,慢慢的理解就行了。在平常代码中我们很少使用总线,但是对于有些公司可能还是经常会用到的,对于那些刚刚接触到总线的朋友们,希望对你们初步理解与简单使用有帮助。