一个简单的消息订阅与广播机制
目录
让应用程序中不同对象之间可以通过发送消息进行通信,而不需要彼此直接引用,从而降低耦合度
// 该类是 单例模式,全局只有一个消息中心。
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