跨进程通信使用MQ,同进程跨多模块(类,或者说跨多业务边界)可使用Event事件驱动思路来解决

C#中委托、事件的好处,只需在某个类中提前定义好公开的委托或事件(委托的特殊表现形式)变量,然后在其它类中就可以很随意的订阅该委托或事件,当委托或事件被触发执行时,会自动通知所有的订阅者进行消费处理。(观察者模式用委托来实现是最好不过了,DDD所提倡的事件驱动其根本理念也是如此),当然我这里想到的是不需要在每个类中进行定义委托或事件,而是由一个统一的中介者(即EventPublishSubscribeUtils)来提供事件的订阅及发布操作,这样各模块之间无需直接依赖,只需通过中介者完成发布通知与订阅回调即可?

1.定义一个事件发布订阅帮助类,EventPublishSubscribeUtils

/// <summary>
/// 自定义事件发布订阅回调工具类(业务解藕、关注点分离,避免互相依赖)
/// 观察者模式   
/// </summary>
public static class EventPublishSubscribeUtils
{
    private static ConcurrentDictionary<Type, EventHandler<object>> EventHandlers { get; } = new ConcurrentDictionary<Type, EventHandler<object>>();

    private static void removeRegisters(ref EventHandler<object> srcEvents, EventHandler<object> removeTargetEvents)
    {
        var evtTypes = removeTargetEvents.GetInvocationList().Select(d => d.GetType());
        var registeredEventHandlers = Delegate.Combine(srcEvents.GetInvocationList().Where(ei => evtTypes.Contains(ei.GetType())).ToArray());
        srcEvents -= (EventHandler<object>)registeredEventHandlers;
    }

    public static void Register<T>(EventHandler<object> eventHandlers)
    {
        EventHandlers.AddOrUpdate(typeof(T), eventHandlers,
            (t, e) =>
            {
                //先根据订阅委托类型匹匹配过滤掉之前已有的相同订阅,然后再重新订阅,防止重复订阅,多次执行的情况。
                removeRegisters(ref e, eventHandlers);
                e += eventHandlers;
                return e;
            });
    }


    public static void UnRegister<T>(EventHandler<object> eventHandlers = null)
    {
        Type eventMsgType = typeof(T);
        if (eventHandlers == null)
        {
            EventHandlers.TryRemove(eventMsgType, out eventHandlers);
            return;
        }

        var e = EventHandlers[eventMsgType];
        removeRegisters(ref e, eventHandlers);
    }

    public static void PublishEvent<T>(T eventMsg, object sender)
    {
        Type eventMsgType = eventMsg.GetType();
        if (EventHandlers.ContainsKey(eventMsgType))
        {
            EventHandlers[eventMsgType].Invoke(sender, eventMsg);
        }
    }
}

2.使用通过EventPublishSubscribeUtils.Register注册订阅事件消息,通过EventPublishSubscribeUtils.PublishEvent发布事件通知

	class EventMessage
	{
		public string Name { get; set; }

		public string Msg { get; set; }

		public DateTime CreatedDate { get; set; }
	}

	class DemoA
	{
		public DemoA()
		{
			EventHandler<object> eventHandlers = EventCallback1;
			eventHandlers += EventCallback2;

			EventPublishSubscribeUtils.Register<EventMessage>(eventHandlers);
		}

		private void EventCallback1(object sender, object e)
		{
			string json = JsonConvert.SerializeObject(e);
			System.Diagnostics.Debug.WriteLine($"EventCallback1=> sender:{sender},e:{json}");
		}

		private void EventCallback2(object sender, object e)
		{
			string json = JsonConvert.SerializeObject(e);
			System.Diagnostics.Debug.WriteLine($"EventCallback2=> sender:{sender},e:{json}");
		}

	}

	class DemoB
	{
		public void ShowMsg(string name, string msg)
		{
			System.Diagnostics.Debug.WriteLine($"ShowMsg=> name:{name},msg:{msg}");
			var eventMsg = new EventMessage
			{
				Name = name,
				Msg = msg,
				CreatedDate = DateTime.Now
			};
			EventPublishSubscribeUtils.PublishEvent(eventMsg, nameof(DemoB.ShowMsg));
		}
	}

//main方法中使用:
var demoA = new DemoA();
var demoB = new DemoB();

demoB.ShowMsg("放假通知", "世界那么大,我想去看看。");

从上述示例代码中可以看出,DemoA与DemoB各为独立,互不依赖,它们都不知道有对方的存在,它们只关心业务的处理,通过执行demoB.ShowMsg方法进而触发回调demoA.EventCallback1,demoA.EventCallback2方法,是不是比起直接从DemoA中调DemoB更好呢?

通过简单的关系图来对比未引用EventPublishSubscribeUtils前与引用后的区别。

来源链接:https://www.cnblogs.com/chenshibao/p/18850559

© 版权声明
THE END
支持一下吧
点赞5 分享
评论 抢沙发
头像
请文明发言!
提交
头像

昵称

取消
昵称表情代码快捷回复

    暂无评论内容