问题
通常情况下,一个中小型软件会包含大概在50个窗体以内,不免会在窗体之间需要传递多种信息和数据。通常有几种方式:
全局变量
- 通过设立全局变量,使得所有的窗体均可以访问的到。
- 使用一个小型化的数据库例如sqlite或者配置文件来进行数据的传递。
但是以上这两种方法均无法实现及时响应。接收数据端需要不断的刷新查询全局变量或者配置文件,造成一定的性能浪费和损失,也丢失了一定的实时响应特性。况且很多软件其实并不需要附带一个本地数据库。
事件
为了解决及时响应,可以通过在窗体中添加事件,通过delegate和invoke来实现及时响应。这个方法在代码量不大或者需要发送接收数据的对象比较少的时候还是比较方便的,一旦需要发送接收数据的对象开始多起来,需要处理的代码就呈现几何级增长。极大的增加了软件的复杂度。
解决方法
使用发布订阅消息队列模式模式。整体四路借鉴了MQTT
这里需要创建两个角色,一个是全局的消息队列中心,队列中心维护订阅发布客户端和订阅主题列表,提供订阅,发布功能。另一个是订阅发布客户端,客户端提供提供订阅,发布和响应事件。
客户端可以订阅多个主题,甚至订阅主题可以带有通配符来进行多个主题的订阅。
代码如下
MQCenter
public static class MQCenter
{
/// <summary>
/// 表示是否运行中
/// </summary>
public static bool IsRunning { get; private set; }
/// <summary>
/// 订阅列表
/// </summary>
public static List<SubscribeTopic> SubscriberList { get; set; }
/// <summary>
/// 启用MQCenter
/// </summary>
public static void Start() { SubscriberList = new List<SubscribeTopic>(); IsRunning = true; }
/// <summary>
/// 停用MQCenter
/// </summary>
public static void Stop() { SubscriberList = null; IsRunning = false; }
/// <summary>
/// 订阅
/// </summary>
/// <param name="Topic">主题</param>
/// <param name="client">客户端实例</param>
public static void Subscribe(string Topic, MQClient client)
{
//.....
}
/// <summary>
/// 取消订阅
/// </summary>
/// <param name="Topic">主题</param>
/// <param name="client">客户端实例</param>
public static void Unsubscribe(string Topic, MQClient client)
{
//.....
}
/// <summary>
/// 发布
/// </summary>
/// <param name="Topic">主题</param>
/// <param name="Payload">负载</param>
public static void Publish(string Topic, string Payload)
{
if (!IsRunning) return;
foreach (var suber in SubscriberList)
{
if (TopicMatch(Topic, suber.Topic))
{
foreach (var item in suber.Clients)
{
item.RaiseMessageReceived(Topic, Payload);
}
}
}
}
private static bool TopicMatch(string pubTopic, string subTopic)
{
//...
}
/// <summary>
/// 获得该客户端所有订阅的主题
/// </summary>
/// <param name="client">客户端实例</param>
/// <returns>已经订阅的主题</returns>
public static string[] GetSubscribeTopics(MQClient client)
{
//...;
}
}
/// <summary>
/// 订阅主题实体
/// </summary>
public class SubscribeTopic
{
/// <summary>
/// 主题
/// </summary>
public string Topic { get; set; }
/// <summary>
/// 订阅该主题的客户端列表
/// </summary>
public List<MQClient> Clients { get; set; }
/// <summary>
/// 创建一个订阅主题实体
/// </summary>
public SubscribeTopic() { Clients = new List<MQClient>(); }
/// <summary>
/// 使用指定的主题创建订阅主题实体
/// </summary>
/// <param name="Topic">主题</param>
public SubscribeTopic(string Topic)
{
this.Topic = Topic;
Clients = new List<MQClient>();
}
}
MQClient
public class MQClient
{
public Guid Id { get; private set; }
public MQClient() { this.Id = new Guid(); }
public MQClient(Guid Id) { this.Id = Id; }
public void Subscribe(string Topic) => MQCenter.Subscribe(Topic, this);
public void Unsubscribe(string Topic) => MQCenter.Unsubscribe(Topic, this);
public void Publish(string Topic, string payload) => MQCenter.Publish(Topic, payload);
public void GetSubscribeTopics() => MQCenter.GetSubscribeTopics(this);
public event EventHandler<MQEventArgs> MessageReceived;
public void RaiseMessageReceived(string Topic, string payload) => MessageReceived?.Invoke(this, new MQEventArgs(Topic, payload));
}
public class MQEventArgs : EventArgs
{
public string Topic { get; set; }
public string Payload { get; set; }
public MQEventArgs() { }
public MQEventArgs(string Topic, string Payload) { this.Topic = Topic; this.Payload = Payload; }