经过几天的努力拜读大牛高手文章,终于对事件总线有所了解,特此记录下来,以免忘记

1、定义相关的接口:

  A  事件接口

 public interface IDomainEvent
{
DateTime OccurredOn(); /// <summary>
/// 设置为已读
/// </summary>
/// <returns></returns>
void Read(); /// <summary>
/// 是否已读
/// </summary>
bool IsRead { get; }
}

  B  事件订阅接口

    public interface IDomainEventSubscriber
{
Type SubscribedToEventType(); void Handle(object domainEvent);
}

2、定义相关实现

  A  事件实现

 public abstract class DomainEvent :  IDomainEvent
{
public readonly DateTime OccurredOnTime;
public string ID; protected DomainEvent()
{
this.ID = Guid.NewGuid().ToString();
this.OccurredOnTime = DateTime.Now;
this.IsRead = false;
} public DateTime OccurredOn()
{
return this.OccurredOnTime;
} public void Read()
{
this.IsRead = true;
} public bool IsRead { get; private set; }
}

  B  事件订阅实现

    public abstract class DomainEventSubscriber<T> : IDomainEventSubscriber where T : IDomainEvent
{
/// <summary>订阅的事件类型
/// </summary>
/// <returns></returns>
public Type SubscribedToEventType()
{
return typeof(T);
} public abstract void HandleEvent(T domainEvent); public void Handle(object domainEvent)
{
if (domainEvent is T)
{
this.HandleEvent((T)domainEvent);
}
else
{
throw new NotSupportedException(string.Format("当前订阅者支持的事件类型是:{0},当前事件是:{1}", typeof(T).FullName, domainEvent.GetType().FullName));
}
}
}

3、定义事件总线实现

 public class DomainEventBus
{
public delegate void DistributeExceptionHandle(IDomainEventSubscriber subscriber, IDomainEvent domainEvent, Exception exception);
/// <summary>
/// Key:DomainEvent的类型,Value订阅该类型事件的订阅者列表
/// </summary>
private static readonly Dictionary<Type, List<IDomainEventSubscriber>> _subscribers = new Dictionary<Type, List<IDomainEventSubscriber>>(); private static readonly object _lockObj = new object(); public event DistributeExceptionHandle DistributeExceptionEvent; private static DomainEventBus _instance;
public static DomainEventBus Instance()
{
if (_instance != null)
return _instance;
var temp = new DomainEventBus();
Interlocked.CompareExchange(ref _instance, temp, null);
return temp;
} public void Publish<T>(T aDomainEvent) where T : IDomainEvent
{
if (aDomainEvent.IsRead)
return; var registeredSubscribers = _subscribers;
if (registeredSubscribers != null)
{
var domainEventType = aDomainEvent.GetType();
List<IDomainEventSubscriber> subscribers;
if (!registeredSubscribers.TryGetValue(domainEventType, out subscribers))
{
aDomainEvent.Read(); //未找到订阅者,但是消息还是消费掉。
return;
} foreach (var domainEventSubscriber in subscribers)
{
var subscribedTo = domainEventSubscriber.SubscribedToEventType();
if (subscribedTo == domainEventType || subscribedTo is IDomainEvent)
{
Distribute(domainEventSubscriber, aDomainEvent);
}
} aDomainEvent.Read();
}
} private void Distribute(IDomainEventSubscriber subscriber, IDomainEvent domainEvent)
{
try
{
subscriber.Handle(domainEvent);
}
catch (Exception ex)
{
OnDistributeExceptionEvent(subscriber, domainEvent, ex);
}
} public void Subscribe(IDomainEventSubscriber aSubscriber)
{
lock (_lockObj)
{
var registeredSubscribers = _subscribers; var domainEventType = aSubscriber.SubscribedToEventType();
List<IDomainEventSubscriber> subscribers; if (!registeredSubscribers.TryGetValue(domainEventType, out subscribers))
{
subscribers = new List<IDomainEventSubscriber>();
registeredSubscribers.Add(domainEventType, subscribers);
} if (subscribers.Any(ent => ent.SubscribedToEventType().FullName == aSubscriber.SubscribedToEventType().FullName && ent.GetType().FullName == aSubscriber.GetType().FullName)) //相同的订阅只接收一次。
return; subscribers.Add(aSubscriber);
}
} protected virtual void OnDistributeExceptionEvent(IDomainEventSubscriber subscriber, IDomainEvent domainEvent, Exception exception)
{
var handler = DistributeExceptionEvent;
if (handler != null)
handler(subscriber, domainEvent, exception);
}
}

4、定义具体的事件

public class OrderCreated : DomainEventCore.DomainEvent
{
public string OrderId { get; private set; } public string UserId { get; private set; } public string Receiver { get; private set; } public OrderCreated(string orderId, string userId, string receiver)
{
this.OrderId = orderId;
this.UserId = userId;
this.Receiver = receiver;
}
}

5、定义具体事件触发后要执行的方法

 public class OrderCreatedSubscriberPaymentContext : DomainEventSubscriber<OrderCreated>
{
public override void HandleEvent(OrderCreated domainEvent)
{
//TODO anything
Console.WriteLine("Order ID:{0},i have payment",domainEvent.OrderId);
}
}
 public class OrderCreatedSubscriberSellingPriceContext : DomainEventSubscriber<OrderCreated>
{
public override void HandleEvent(OrderCreated domainEvent)
{
//TODO anything
Console.WriteLine("Order ID:{0},i have show price", domainEvent.OrderId);
}
}

6、代码测试

class Program
{
static void Main(string[] args)
{
//事件订阅
DomainEventBus.Instance().Subscribe(new OrderCreatedSubscriberSellingPriceContext());
DomainEventBus.Instance().Subscribe(new OrderCreatedSubscriberPaymentContext()); var tempGuid = Guid.NewGuid().ToString();
var entity = new OrderCreated(tempGuid, "mikechang", "sprite");
Console.WriteLine("生产一个新的订单:{0}",tempGuid);
//事件发布
DomainEventBus.Instance().Publish(entity);
Console.ReadLine();
}
}

事件总线demo的更多相关文章

  1. android开源项目之OTTO事件总线(二)官方demo解说

    官方demo见  https://github.com/square/otto 注意自己该编译版本为2.3以上,默认的1.6不支持match_parent属性,导致布局文件出错. 另外需要手动添加an ...

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

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

  3. 事件总线帧---Otto

    我们如果这样一种业务场景.如今在做一款及时聊天应用,我们在聊天页面进行收发信息.同一时候也要实时更新前一页面的聊天记录,这时我们该怎样去实现?说说我曾经的实现策略.我使用的是广播接收器BroadCas ...

  4. 【第一篇】学习 android 事件总线androidEventbus之sticky事件的传递

    最近再看eventbus相关代码,首先从使用开始,后期再从源码角度分析eventbus.使用Demo后期公布到github上去. 使用的框架地址:https://github.com/bboyfeiy ...

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

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

  6. Android事件总线分发库EventBus3.0的简单讲解与实践

    Android事件总线分发库EventBus的简单讲解与实践 导语,EventBus大家应该不陌生,EventBus是一款针对Android优化的发布/订阅事件总线.主要功能是替代Intent,Han ...

  7. Autofac解耦事件总线

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

  8. C# 事件总线 EventBus

    1. 引言 事件总线这个概念对你来说可能很陌生,但提到观察者(发布-订阅)模式,你也许就很熟悉.事件总线是对发布-订阅模式的一种实现.它是一种集中式事件处理机制,允许不同的组件之间进行彼此通信而又不需 ...

  9. 事件总线(Event Bus)

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

随机推荐

  1. OGG_GoldenGate数据控制进程Manager(案例)

    2014-03-03 Created By BaoXinjian

  2. git配置gitignore

    一.背景                                                                                                 ...

  3. js数组设置值操作

    js中给数组中添加新值的方式: var flow=[]; for(var i=0;i<21;i++){ flow.push(Math.floor(Math.random()*(30+((i%12 ...

  4. unity, 让主角头顶朝向等于地面法线(character align to surface normal)

    计算过程如下: 1,通过由主角中心raycast一条竖直射线获得主角所在处地面法线,用作主角的newUp. 注:一定要从主角中心raycast,而不要从player.transform.positio ...

  5. NUMA体系结构详解

    1. NUMA的几个概念(Node,socket,core,thread) 对于socket,core和thread会有不少文章介绍,这里简单说一下,具体参见下图: 一句话总结:socket就是主板上 ...

  6. hadoop(2.x)以hadoop2.2为例完全分布式最新高可靠安装文档

    问题导读:1.如何配置各个节点之间无密码互通?2.启动hadoop,看不到进程的原因是什么?3.配置hadoop的步骤是什么? 4.有哪些配置文件需要修改?5.如果没有配置文件,该如何找到该配置文件? ...

  7. gitbook安装与使用

    废话不说,直接主题: gitbook安装 =========== 1. 安装npm  从站点 https://nodejs.org/#download 下载node.js源码(点击绿色的INSTALL ...

  8. codeforces 482B. Interesting Array【线段树区间更新】

    题目:codeforces 482B. Interesting Array 题意:给你一个值n和m中操作,每种操作就是三个数 l ,r,val. 就是区间l---r上的与的值为val,最后问你原来的数 ...

  9. error: expected expression before 'struct'

    错误原因: 使用了offsetof函数,却没有包含头文件<stddef.h> 解决办法: 包含<stddef.h>

  10. Socket相关函数(2)- sendto(), recvfrom() UDP模型

    udp_server.c #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #in ...