最近在空闲时间准备做个小游戏,先把一些基本框架搭建好,本次记录的是消息的注册,监听和回调等
其实这些就是基于C#的委托(delegate)
第一步:定义一些委托
namespace Common.Messenger { public delegate void Callback(); public delegate void Callback<T>(T arg1); public delegate void Callback<T, U>(T arg1, U arg2); public delegate void Callback<T, U, V>(T arg1, U arg2, V arg3); public delegate void Callback<T, U, V, W>(T arg1, U arg2, V arg3, W arg4); public delegate void Callback<T, U, V, W, X>(T arg1, U arg2, V arg3, W arg4, X arg5); public delegate void Callback<T, U, V, W, X, Y>(T arg1, U arg2, V arg3, W arg4, X arg5, Y arg6); public delegate T CallbackReturn<T>(); public delegate T CallbackReturn<T, U>(U arg1); }
用泛型的方式灵活运用各种消息处理
第二步:定义两个Message类,用于add/remove/brocast消息
namespace Common.Messenger { public enum MessengerMode : byte { DONT_REQUIRE_LISTENER, REQUIRE_LISTENER, } private static internal class MessengerInternal { //...... } public static class Messenger { //.... } }
MessengerInternal类:用于存放消息类型,结构Dictionary<string,Delegate>
static internal class MessengerInternal { public static Dictionary<string, Delegate> eventTable = new Dictionary<string, Delegate>(); public static readonly MessengerMode DEFAULT_MODE = MessengerMode.DONT_REQUIRE_LISTENER; public static void OnListenerAdding(string eventType, Delegate listenerBeingAdded) { if (!eventTable.ContainsKey(eventType)) eventTable.Add(eventType, null); Delegate d = eventTable[eventType]; if(d!=null&&d.GetType()!=listenerBeingAdded.GetType()) throw new ListenerException(string.Format("Attempting to add listener with inconsistent signature for event type {0}. Current listeners have type {1} and listener being added has type {2}", eventType, d.GetType().Name, listenerBeingAdded.GetType().Name)); } public static void OnListenerMoving(string eventType,Delegate listenerBeingRemoved) { if (eventTable.ContainsKey(eventType)) { Delegate d = eventTable[eventType]; if (d == null) throw new ListenerException(string.Format("Attempting to remove listener with for event type {0} but current listener is null.", eventType)); else if(d.GetType()!=listenerBeingRemoved.GetType()) throw new ListenerException(string.Format("Attempting to remove listener with inconsistent signature for event type {0}. Current listeners have type {1} and listener being removed has type {2}", eventType, d.GetType().Name, listenerBeingRemoved.GetType().Name)); } else throw new ListenerException(string.Format("Attempting to remove listener for type {0} but Messenger doesn't know about this event type.", eventType)); } public static void OnListenerRemoved(string eventType) { if (eventTable[eventType] == null) eventTable.Remove(eventType); } public static void OnBroadcasting(string eventType, MessengerMode mode) { if(mode==MessengerMode.REQUIRE_LISTENER&&!eventTable.ContainsKey(eventType)) throw new MessengerInternal.BroadcastException(string.Format("Broadcasting message {0} but no listener found.", eventType)); } static public BroadcastException CreateBroadcastSignatureException(string eventType) { return new BroadcastException(string.Format("Broadcasting message {0} but listeners have a different signature than the broadcaster.", eventType)); } public class BroadcastException : Exception { public BroadcastException(string msg) : base(msg) { } } public class ListenerException : Exception { public ListenerException(string msg):base(msg) { } } }
Messenger类:Public类型,用于外界的调用,封装了AddListener/Remove/Brocast的方法
public static class Messenger { private static Dictionary<string, Delegate> eventTable = MessengerInternal.eventTable; public static void AddListener(string eventType,Callback handler) { MessengerInternal.OnListenerAdding(eventType, handler); eventTable[eventType] = (Callback)eventTable[eventType] + handler; } public static void RemoveListener(string eventType, Callback handler) { MessengerInternal.OnListenerMoving(eventType, handler); eventTable[eventType] = (Callback)eventTable[eventType] - handler; MessengerInternal.OnListenerRemoved(eventType); } public static void Broadcast(string eventType) { Broadcast(eventType, MessengerInternal.DEFAULT_MODE); } public static void Broadcast(string eventType, MessengerMode mode) { MessengerInternal.OnBroadcasting(eventType, mode); Delegate d; if (eventTable.TryGetValue(eventType, out d)) { Callback callback = d as Callback; if (callback != null) callback(); else throw MessengerInternal.CreateBroadcastSignatureException(eventType); } } }
Messenger<T>类:含参数的扩展类
public static class Messenger<T> { private static Dictionary<string, Delegate> eventTable = MessengerInternal.eventTable; public static void AddListener(string eventType, Callback<T> handler) { MessengerInternal.OnListenerAdding(eventType, handler); eventTable[eventType] = (Callback<T>)eventTable[eventType] + handler; } public static void RemoveListener(string eventType, Callback<T> handler) { MessengerInternal.OnListenerMoving(eventType, handler); eventTable[eventType] = (Callback<T>)eventTable[eventType] - handler; } public static void Broadcast(string eventType, T arg1) { Broadcast(eventType, arg1, MessengerInternal.DEFAULT_MODE); } public static void Broadcast(string eventType, T arg1, MessengerMode mode) { MessengerInternal.OnBroadcasting(eventType, mode); Delegate d; if (eventTable.TryGetValue(eventType,out d)) { Callback<T> callback = d as Callback<T>; if (callback != null) callback(arg1); } else throw MessengerInternal.CreateBroadcastSignatureException(eventType); } }
Messenger<T, U>:同上
举例:下面是一个消息弹窗例子
UI层调用
void OnStartClick(GameObject go) { UIMessageMgr.ShowMessBox("?????", () => { Debug.Log("Success"); }); }
UIMessageMgr:
public static void ShowMessBox(string content, Callback ok) { Messenger<string, Callback>.Broadcast(MessengerEventDef.ShowMessBox, content, ok);
//MessengerEventDef.ShowMessBox 是一个string,也就是Dictionary<>中的key }
注册:
public override void RegisterMessage() { Messenger<string, Callback>.AddListener(MessengerEventDef.ShowMessBox, ShowMessBox); }
移除监听:
public override void RemoveMessage() { Messenger<string, Callback>.RemoveListener(MessengerEventDef.ShowMessBox, ShowMessBox); }
以上功能就是通过消息来显示提示框,使用的Message<T,U>,普通的消息可以用Message<T>
Client和Server之间的协议通信也用消息,Message<协议类>
//Message<协议类>.AddListener("这是一个字符串",回调方法) //回调方法
//function(协议类)
//{
// 执行内容
//} //Remove同上 //分发消息在接收到server的消息时把消息brocast //function(协议类) //{ // Message<协议类>.Brocast("这是一个字符串",协议类) //}