目录

一个简单的消息订阅与广播机制

目录

让应用程序中不同对象之间可以通过发送消息进行通信,而不需要彼此直接引用,从而降低耦合度

  // 该类是 单例模式,全局只有一个消息中心。
  public class SimpleMessenger
  {
      // 存储单例实例
      private static readonly SimpleMessenger _instance = new SimpleMessenger();

      // 提供全局访问入口
      public static SimpleMessenger Default => _instance;

      // 保存所有消息类型与对应订阅者的回调函数
      private readonly Dictionary<Type, List<Delegate>> _subscribers = new Dictionary<Type, List<Delegate>>();

      /// <summary>
      /// 注册订阅者,监听某种类型的消息
      /// </summary>
      /// <typeparam name="TMessage">监听的消息类型</typeparam>
      /// <param name="callback">收到消息时要执行的方法</param>
      /// <remarks> 1.判断该消息类型是否存在订阅表中. 若没有则创建一个List<Delegate> </remarks>
      /// <remarks> 2.将回调方法保存到字典中相关消息类型的列表里</remarks>
      /// 注册后,该方法会Send<TMessage>时被执行
      public void Register<TMessage>(Action<TMessage> callback)
      {
          var messageType = typeof(TMessage);
          if (!_subscribers.ContainsKey(messageType))
          {
              _subscribers[messageType] = new List<Delegate>();
          }

          _subscribers[messageType].Add(callback);
      }

      /// <summary>
      /// 取消订阅指定类型消息
      /// </summary>
      /// <typeparam name="TMessage">监听的消息类型</typeparam>
      /// <param name="callback">收到消息时要执行的方法</param>
      /// <remarks> 1. 从 _subscribers 字典中删除指定回调 </remarks>
      /// <remarks> 2. 如果该消息类型没有订阅者了,则整个键值对删掉 </remarks>
      /// 用于防止内存泄露和不必要的回调触发
      public void Unregister<TMessage>(Action<TMessage> callback)
      {
          var messageType = typeof(TMessage);
          if (_subscribers.ContainsKey(messageType))
          {
              _subscribers[messageType].Remove(callback);
              if (_subscribers[messageType].Count == 0)
              {
                  _subscribers.Remove(messageType);
              }
          }
      }


      /// <summary>
      /// 发送消息并触发所有已注册该类型消息的回调
      /// </summary>
      /// <typeparam name="TMessage">监听的消息类型</typeparam>
      /// <param name="message"></param>
      /// <remarks> 查找该消息类型是否有人订阅,如果有则遍历执行所有对应 Action<TMessage> 回调 </remarks>
      public void Send<TMessage>(TMessage message)
      {
          var messageType = typeof(TMessage);
          if (_subscribers.ContainsKey(messageType))
          {
              foreach (var action in _subscribers[messageType].ToList())
              {
                  (action as Action<TMessage>)?.Invoke(message);
              }
          }
      }
  }

使用示例

SimpleMessenger.Default.Register<string>(msg => Console.WriteLine("收到消息:" + msg));

SimpleMessenger.Default.Send("Hello World");

输出:

收到消息:Hello World