什么是订阅发布者模式?简单的说,比如我看见有人在公交车上偷钱包,于是大叫一声“有人偷钱包”(发送消息),车上的人听到(接收到消息)后做出相应的反应,比如看看自己的钱包什么的。其实就两个步骤,注册消息与发送消息。
为了适应项目需要,写了一个通用订阅发布者模式的通用模块,有了这样一个模块,项目里面其他模块之间的耦合性也将大大降低。
话不多说,直接上代码。
消息分发中心:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 消息分发中心.
/// </summary>
public class DispatcherCenter
{
private static Logger logger = LogHelper.GetLogger("DispatcerCenter");
private static DispatcherCenter instance;
public static DispatcherCenter Instance
{
get
{
if (instance == null)
{
instance = new DispatcherCenter();
}
return instance;
}
}
private Dictionary<int, List<Observer>> map = new Dictionary<int, List<Observer>>();
/// <summary>
/// 发送消息.
/// </summary>
/// <param name="type">消息类型.</param>
/// <param name="msg">消息内容.</param>
public void SendNotification(int type, object msg)
{
if (map.ContainsKey(type))
{
List<Observer> observers = map[type];
foreach (Observer obs in observers)
{
Notification notice = new Notification(type, msg);
if(obs.handler != null)
{
obs.handler(notice);
}
}
}
else
{
if (msg == null)
{
logger.Error("分发消息失败,未注册该消息!!! Type: " + type + " Msg is null.");
}
else
{
logger.Error("分发消息失败,未注册该消息!!! Type: " + type + " Msg: " + msg);
}
}
}
/// <summary>
/// 注册消息.
/// </summary>
/// <param name="type">消息类型.</param>
/// <param name="handler">收到消息的回调.</param>
public void RegisterObserver(int type, NotificationHandler handler)
{
List<Observer> observers = null;
if (map.TryGetValue(type, out observers))
{
foreach (Observer obs in observers)
{
if (obs.handler == handler)
{
//logger.Debug("该回调已经注册,不能重复注册!");
return;
}
}
observers.Add(new Observer(type, handler));
}
else
{
observers = new List<Observer>();
observers.Add(new Observer(type, handler));
map.Add(type, observers);
}
}
/// <summary>
/// 移除消息.
/// </summary>
/// <param name="type">消息类型.</param>
/// <param name="handler">收到消息的回调.</param>
public void RemoveObserver(int type, NotificationHandler handler)
{
List<Observer> observers = map[type];
if (map.TryGetValue(type, out observers))
{
foreach (Observer obs in observers)
{
if(obs.handler == handler)
{
observers.Remove(obs);
//bool result = observers.Remove(obs);
//logger.Debug("消息移除是否成功: " + result);
return;
}
}
logger.Error("移除失败,未找到该回调!!! Type: " + type);
}
else
{
logger.Error("移除失败,未注册该消息!!! Type: " + type);
}
}
}
订阅者:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//接收到消息的回调.
public delegate void NotificationHandler(Notification notice);
/// <summary>
/// 观察者.
/// </summary>
public class Observer
{
public NotificationHandler handler;
public Observer() { }
public Observer(int type, NotificationHandler handler)
{
this.handler += handler;
}
}
消息类:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 消息类.
/// </summary>
public class Notification
{
private int type;
private object msg;
public int Type { get { return type; } }
public object Msg { get { return msg; } }
public Notification(int type, object msg)
{
this.type = type;
this.msg = msg;
}
public override string ToString()
{
if (msg != null)
{
return string.Format("Type:{0} Msg:{1}", type, msg.ToString());
}
return string.Format("Type:{0} Msg is null", type);
}
}
消息:(我用的是枚举表示,然后强转为int值来识别是哪个消息,枚举值不能重复)
/// <summary>
/// 消息枚举.
/// </summary>
public class NotificationEnum
{
public enum ModelNotices
{
SEPARATE = 0,
MERGE
}
public enum OtherNotice
{
OTHER1 = 101,
OTHER2
}
}
那么如何使用呢?
还是看代码,首先在Notifications中添加要注册的消息号,然后在合适时候调用RegisterNotifications()注册消息,在NotificationHandler()中根据消息号做出相应的操作。在不需要再观察消息的时候移除消息RemoveNotifications();
using UnityEngine;
public class Test : MonoBehaviour
{
private void Awake()
{
RegisterNotifications();
}
private void OnDestory()
{
RemoveNotifications();
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.F1))
{
UnityEngine.Debug.Log("---------->>>> 分离消息.");
//消息内容可以是任何东西,如int值,类 DispatcherCenter.Instance.SendNotification((int)NotificationEnum.ModelNotices.SEPARATE, null);
}
if (Input.GetKeyDown(KeyCode.F2))
{
UnityEngine.Debug.Log("---------->>>> 合并消息.");
//消息内容可以是任何东西,如int值,类 DispatcherCenter.Instance.SendNotification((int)NotificationEnum.ModelNotices.MERGE, null);
}
//if (Input.GetKeyDown(KeyCode.F1))
//{
// Debug.Log("Test1 注册消息.");
// RegisterNotifications();
//}
//if (Input.GetKeyDown(KeyCode.Keypad1))
//{
// Debug.Log("Test1 移除消息.");
// RemoveNotifications();
//}
}
#region 消息相关
//需注册的消息. TODO
private int[] Notifications
{
get
{
return new int[]
{
(int)NotificationEnum.ModelNotices.SEPARATE,
(int)NotificationEnum.ModelNotices.MERGE
};
}
}
private void RegisterNotifications()
{
for (int i = 0; i < Notifications.Length; i++)
{
DispatcherCenter.Instance.RegisterObserver(Notifications[i], NotificationHandler);
}
}
private void RemoveNotifications()
{
for (int i = 0; i < Notifications.Length; i++)
{
DispatcherCenter.Instance.RemoveObserver(Notifications[i], NotificationHandler);
}
}
//收到消息的回调 TODO
private void NotificationHandler(Notification notice)
{
if (notice.Type == (int)NotificationEnum.ModelNotices.SEPARATE)
{
UnityEngine.Debug.Log("Test1收到零件分离的消息." + notice.ToString());
}
else if (notice.Type == (int)NotificationEnum.ModelNotices.MERGE)
{
UnityEngine.Debug.Log("Test1收到零件合并的消息." + notice.ToString());
}
}
#endregion
}