眼上秋波 發表於 2025-4-27 22:22:00

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

<p>C#中委托、事件的好处,只需在某个类中提前定义好公开的委托或事件(委托的特殊表现形式)变量,然后在其它类中就可以很随意的订阅该委托或事件,当委托或事件被触发执行时,会自动通知所有的订阅者进行消费处理。(观察者模式用委托来实现是最好不过了,DDD所提倡的事件驱动其根本理念也是如此),当然我这里想到的是不需要在每个类中进行定义委托或事件,而是由一个统一的中介者(即EventPublishSubscribeUtils)来提供事件的订阅及发布操作,这样各模块之间无需直接依赖,只需通过中介者完成发布通知与订阅回调即可?</p>
<h2 id="1定义一个事件发布订阅帮助类eventpublishsubscribeutils">1.定义一个事件发布订阅帮助类,EventPublishSubscribeUtils</h2>
<pre><code>/// &lt;summary&gt;
/// 自定义事件发布订阅回调工具类(业务解藕、关注点分离,避免互相依赖)
/// 观察者模式   
/// &lt;/summary&gt;
public static class EventPublishSubscribeUtils
{
    private static ConcurrentDictionary&lt;Type, EventHandler&lt;object&gt;&gt; EventHandlers { get; } = new ConcurrentDictionary&lt;Type, EventHandler&lt;object&gt;&gt;();

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

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


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

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

    public static void PublishEvent&lt;T&gt;(T eventMsg, object sender)
    {
      Type eventMsgType = eventMsg.GetType();
      if (EventHandlers.ContainsKey(eventMsgType))
      {
            EventHandlers.Invoke(sender, eventMsg);
      }
    }
}
</code></pre>
<h2 id="2使用通过eventpublishsubscribeutilsregister注册订阅事件消息通过eventpublishsubscribeutilspublishevent发布事件通知">2.使用通过EventPublishSubscribeUtils.Register注册订阅事件消息,通过EventPublishSubscribeUtils.PublishEvent发布事件通知</h2>
<pre><code>        class EventMessage
        {
                public string Name { get; set; }

                public string Msg { get; set; }

                public DateTime CreatedDate { get; set; }
        }

        class DemoA
        {
                public DemoA()
                {
                        EventHandler&lt;object&gt; eventHandlers = EventCallback1;
                        eventHandlers += EventCallback2;

                        EventPublishSubscribeUtils.Register&lt;EventMessage&gt;(eventHandlers);
                }

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

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

        }

        class DemoB
        {
                public void ShowMsg(string name, string msg)
                {
                        System.Diagnostics.Debug.WriteLine($"ShowMsg=&gt; 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("放假通知", "世界那么大,我想去看看。");
</code></pre>
<p>从上述示例代码中可以看出,DemoA与DemoB各为独立,互不依赖,它们都不知道有对方的存在,它们只关心业务的处理,通过执行demoB.ShowMsg方法进而触发回调demoA.EventCallback1,demoA.EventCallback2方法,是不是比起直接从DemoA中调DemoB更好呢?</p>
<p>通过简单的关系图来对比未引用EventPublishSubscribeUtils前与引用后的区别。</p>
<p><img src="https://img2024.cnblogs.com/blog/2212230/202504/2212230-20250427222143058-1373263988.png"></p><br><br>
来源:https://www.cnblogs.com/chenshibao/p/18850559
頁: [1]
查看完整版本: 跨进程通信使用MQ,同进程跨多模块(类,或者说跨多业务边界)可使用Event事件驱动思路来解决