C#完成一个应用内的消息中心
本文会讲解如何使用 C#
完成一个应用内部的消息中心(事件总线),事件驱动最大的好处就是可以很大程度的解耦合,松散结构。
模式介绍
简单来说就是一个发布订阅模式设计,对于消息的产生者来说,并不对直接将消息发送给消息的处理者,而是将消息发送给独立的消息中心,这里和观察者模式做个区别。对于消息产生者来说,无需知道有哪些订阅者。而对于订阅者来说,同样无需知道消息发布者的存在。
实现
使用 C#
实现如下,一个消息中心有两个方法,一个是发布消息:Send
/Publish
,有一个是订阅消息:Subscribe
public static class MessageCenter
{
public static void Send(object sender, string name, object data)
{
InnerSend(sender, name, data);
}
public static void Subscribe<TSender, TData>(object subscriber, string name, Action<TSender, TData> action)
{
InnerSubscribe(subscriber, name, action?.Method, action?.Target);
}
}
接着实现 InnerSend
,发布消息本质就是查询所有的订阅者,并执行订阅的响应事件
private static void InnerSend(object sender, string name, object data)
{
if (string.IsNullOrEmpty(name))
throw new NullReferenceException();
if (subs.TryGetValue(name, out var subscriptions))
{
foreach (var subscription in subscriptions)
{
subscription.Invoke(sender, data);
}
}
}
然后是 InnerSubscribe
,将订阅者添加到订阅集合里
private static void InnerSubscribe(object subscriber, string name, MethodInfo methodInfo, object target)
{
if (subscriber == null)
throw new NullReferenceException();
if (string.IsNullOrEmpty(name))
throw new NullReferenceException();
var sub = new Subscription(subscriber, methodInfo, target);
if (subs.ContainsKey(name))
{
subs[name].Add(sub);
return;
}
subs.Add(name, new List<Subscription>() { sub });
}
接下来实现订阅类,他将订阅者规范成统一的类型,方便消息传递
class Subscription
{
public Subscription(object source, MethodInfo methodInfo, object target)
{
Source = source;
MethodInfo = methodInfo;
Target = target;
}
public object Source { get; set; }
public MethodInfo MethodInfo { get; set; }
public object Target { get; set; }
//执行订阅响应
public void Invoke(object sender, object data)
{
if (sender == null || sender == Source) return;
if (MethodInfo.IsStatic)
{
MethodInfo.Invoke(null, MethodInfo.GetParameters().Length == 1 ? new[] { sender } : new[] { sender, data });
return;
}
MethodInfo?.Invoke(Target, MethodInfo.GetParameters().Length == 2 ? new[] { sender, data } : new[] { sender });
}
}
最后,别忘了使用字典把订阅者存下来
public static class MessageCenter
{
private static Dictionary<string, List<Subscription>> subs = new Dictionary<string, List<Subscription>>();
//.....内部代码
}
使用也是非常的方便,Bar
向消息中心订阅通道,Foo
向消息中心推送消息,完成后会打印出从 Foo
传到 Bar
的消息
public class Bar
{
public void Start()
{
MessageCenter.SubScribe<Foo,string>(this, "测试通道", Handle);
}
private void Handle(Foo sender,string data)
{
Console.WriteLine(data);
}
}
public class Foo
{
public void Start()
{
MessageCenter.Send(this, "测试通道", "这是一条测试信息");
}
}
Foo foo = new Foo();
Bar bar = new Bar();
//注意,这里要先注册订阅
bar.Start();
foo.Start();