先考虑需要实现的基本功能: 在任意一个地方增加一个消息的listener,则当这个消息被broadcast的时候,所有的listener都应该收到。
考虑到delegate(我的理解是本身就是为实现观察者模式而出现的类),另外有个dict保存消息名和Delegate的对应。
定义一个static消息类Messenger。
1 static internal class Messenger 2 { 3 private static Dictionary<string, Delegate> eventDict = new Dictionary<string,Delegate>(); 4 }
考虑到委托需要全部代码可见,所以单独放入到一个文件中。
以下实现了4中委托,都是void返回。可以依据需求自己增加。
1 //无参数 2 public delegate void Callback(); 3 //一个参数的模板 4 public delegate void Callback<T>(T t); 5 //两个参数的模板 6 public delegate void Callback<T, U>(T t, U u); 7 8 public delegate void Callback<T,U,V>(T t,U u,V v);
为了进行优化,在load一个新level的时候,考虑将原先的消息都清空。但是有一些消息可能需要一直存在。
所以给messenger 类添加了 CleanUp 函数,一个标记永久消息函数,和一个 list来存储永久消息
1 private static List<string> permenentMessages = new List<string>();
1 public static void SetPermenent(string name) 2 { 3 if(!permenentMessages.Contains(name)) 4 { 5 permenentMessages.Add(name); 6 } 7 }
1 public static void CleanUp() 2 { 3 foreach (var value in eventDict) 4 { 5 if (!permenentMessages.Contains(value.Key)) 6 { 7 eventDict.Remove(value.Key); 8 } 9 } 10 }
添加 MessengerHelp类
1 public sealed class MessengerHelper:MonoBehaviour 2 { 3 private void Awake() 4 { 5 DontDestroyOnLoad(gameObject); 6 } 7 8 public void OnLevelWasLoaded(int unUsed) 9 { 10 //每次新level load 的时候,清理以前的message 。 但有些信息需要保留,通用,所以的话, 就必须有永久信息的存储。list 11 Messenger.CleanUp(); 12 } 13 14 }
Messenger中其他的消息操作(增加,删除,广播,打印)(以无参数为例):
1 /// <summary> 2 /// 打印出所有事件 3 /// </summary> 4 public static void PrintEventDict() 5 { 6 Debug.Log("EventDict as follows"); 7 foreach(var pair in eventDict) 8 { 9 Debug.Log("Event name: " + pair.Key); 10 Debug.Log("Event Delegate: " + pair.Value); 11 } 12 } 13 14 15 public static void OnAdding(string name,Delegate listenerBeingAdded) 16 { 17 if(!eventDict.ContainsKey(name)) 18 { 19 eventDict.Add(name, null); 20 } 21 22 //判断加入的类型与原先存储的类型是否一样 23 Delegate d = eventDict[name]; 24 if(d!=null && d.GetType() != listenerBeingAdded.GetType()) 25 { 26 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}", name, d.GetType().Name, listenerBeingAdded.GetType().Name)); 27 } 28 } 29 static public void OnRemoving(string name,Delegate listenerBeingRemoved) 30 { 31 if(eventDict.ContainsKey(name)) 32 { 33 Delegate d = eventDict[name]; 34 if(d == null) 35 { 36 throw new ListenerException(string.Format("Attempting to remove listener with for name \"{0}\" but current listener is null.", name)); 37 } 38 else if(d.GetType() != listenerBeingRemoved.GetType()) 39 { 40 throw new ListenerException(string.Format("Attempting to remove listener with inconsistent signature for name {0}. Current listeners have type {1} and listener being removed has type {2}", name, d.GetType().Name, listenerBeingRemoved.GetType().Name)); 41 42 } 43 } 44 else 45 { 46 throw new ListenerException(string.Format("Attempting to remove listener for name \"{0}\" but Messenger doesn‘t know about this name.", name)); 47 } 48 } 49 /// <summary> 50 /// 每次移除后查看name对应的value是否为空 51 /// </summary> 52 /// <param name="name"></param> 53 static public void OnRemoved(string name) 54 { 55 if(eventDict[name] == null) 56 { 57 eventDict.Remove(name); 58 } 59 } 60 static public void OnBroadcasting(string name) 61 { 62 #if REQUIRE_LISTENER 63 if (!eventDict.ContainsKey(name)) 64 { 65 throw new BroadcastException(string.Format("Broadcasting message \"{0}\" but no listener found. Try marking the message with Messenger.MarkAsPermanent.", name)); 66 } 67 #endif 68 } 69 70 71 static public void AddListener(string name, Callback listenerBeingAdded) 72 { 73 OnAdding(name,listenerBeingAdded); 74 //存储这个name 对应的delegate 75 eventDict[name] = (Callback)eventDict[name] + listenerBeingAdded; 76 } 77 78 static public void RemoveListener(string name, Callback ListenerBeingRemoved) 79 { 80 //移除前检查 81 OnRemoving(name, ListenerBeingRemoved); 82 eventDict[name] = (Callback)eventDict[name] - ListenerBeingRemoved; 83 //移除后检查 84 OnRemoved(name); 85 } 86 87 88 public static void BroadCast(string name) 89 { 90 OnBroadcasting(name); 91 92 Delegate d; 93 if(eventDict.TryGetValue(name,out d)) 94 { 95 Callback callback = d as Callback; 96 97 if(callback != null) 98 { 99 callback(); 100 } 101 else 102 { 103 throw CreateBroadcastSignatureException(name); 104 } 105 } 106 }
使用方式:
1 using UnityEngine; 2 using System.Collections; 3 4 public class UseMessenger : MonoBehaviour 5 { 6 int health = 100; 7 8 void Awake() 9 { 10 Messenger.AddListener("LoseHealth", LoseHealth); 11 Messenger.AddListener("LoseHealth", LoseHealthTwo); 12 Messenger.AddListener("LoseHealthLoseHealth", LoseHealth); 13 Messenger.AddListener<int, string, bool>("FOO", Foo); 14 } 15 16 void Update() 17 { 18 Debug.Log(health); 19 } 20 21 void LoseHealth() 22 { 23 health -= 10; 24 } 25 26 void LoseHealthTwo() 27 { 28 health -= 10; 29 } 30 31 void Foo(int number,string name,bool isTrue) 32 { 33 Debug.Log(number); 34 Debug.Log(name); 35 Debug.Log(isTrue); 36 } 37 }
1 using UnityEngine; 2 using System.Collections; 3 4 public class BroadCast : MonoBehaviour 5 { 6 7 void Start() 8 { 9 Messenger.BroadCast("LoseHealth"); 10 Messenger.SetPermenent("LoseHealth"); 11 Messenger.BroadCast<int, string, bool>("FOO",100, "nice", true); 12 13 Messenger.PrintEventDict(); 14 15 } 16 }
执行结果:
所有的代码如下。
1 #define REQUIRE_LISTENER 2 3 using UnityEngine; 4 using System.Collections; 5 using System.Collections.Generic; 6 using System; 7 8 /// <summary> 9 /// 消息处理框架 10 /// </summary> 11 static internal class Messenger //static internal 12 { 13 14 static private MessengerHelper messengerHelper = (new GameObject("MessengerHelper")).AddComponent<MessengerHelper>(); 15 //存储暂时的消息,关卡load时清空 16 //不同类型的delegate存储在同一个字典中,用大写的Delegate表示类型。 在System 下 17 //此处value值只能为delegate,而不能选择event。 所以说只是利用了delegate 而没有使用event。为了简洁; 18 private static Dictionary<string, Delegate> eventDict = new Dictionary<string,Delegate>(); 19 //存储永久的消息,清空时忽略list中的消息 20 private static List<string> permenentMessages = new List<string>(); 21 22 /// <summary> 23 /// 打印出所有事件 24 /// </summary> 25 public static void PrintEventDict() 26 { 27 Debug.Log("EventDict as follows"); 28 foreach(var pair in eventDict) 29 { 30 Debug.Log("Event name: " + pair.Key); 31 Debug.Log("Event Delegate: " + pair.Value); 32 } 33 } 34 35 /// <summary> 36 /// 标记为永久有效 37 /// </summary> 38 /// <param name="name"></param> 39 public static void SetPermenent(string name) 40 { 41 if(!permenentMessages.Contains(name)) 42 { 43 permenentMessages.Add(name); 44 } 45 } 46 /// <summary> 47 /// 清理 48 /// </summary> 49 public static void CleanUp() 50 { 51 foreach (var value in eventDict) 52 { 53 if (!permenentMessages.Contains(value.Key)) 54 { 55 eventDict.Remove(value.Key); 56 } 57 } 58 } 59 public static void OnAdding(string name,Delegate listenerBeingAdded) 60 { 61 if(!eventDict.ContainsKey(name)) 62 { 63 eventDict.Add(name, null); 64 } 65 66 //判断加入的类型与原先存储的类型是否一样 67 Delegate d = eventDict[name]; 68 if(d!=null && d.GetType() != listenerBeingAdded.GetType()) 69 { 70 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}", name, d.GetType().Name, listenerBeingAdded.GetType().Name)); 71 } 72 } 73 static public void OnRemoving(string name,Delegate listenerBeingRemoved) 74 { 75 if(eventDict.ContainsKey(name)) 76 { 77 Delegate d = eventDict[name]; 78 if(d == null) 79 { 80 throw new ListenerException(string.Format("Attempting to remove listener with for name \"{0}\" but current listener is null.", name)); 81 } 82 else if(d.GetType() != listenerBeingRemoved.GetType()) 83 { 84 throw new ListenerException(string.Format("Attempting to remove listener with inconsistent signature for name {0}. Current listeners have type {1} and listener being removed has type {2}", name, d.GetType().Name, listenerBeingRemoved.GetType().Name)); 85 86 } 87 } 88 else 89 { 90 throw new ListenerException(string.Format("Attempting to remove listener for name \"{0}\" but Messenger doesn‘t know about this name.", name)); 91 } 92 } 93 /// <summary> 94 /// 每次移除后查看name对应的value是否为空 95 /// </summary> 96 /// <param name="name"></param> 97 static public void OnRemoved(string name) 98 { 99 if(eventDict[name] == null) 100 { 101 eventDict.Remove(name); 102 } 103 } 104 static public void OnBroadcasting(string name) 105 { 106 #if REQUIRE_LISTENER 107 if (!eventDict.ContainsKey(name)) 108 { 109 throw new BroadcastException(string.Format("Broadcasting message \"{0}\" but no listener found. Try marking the message with Messenger.MarkAsPermanent.", name)); 110 } 111 #endif 112 } 113 114 #region AddListener 115 static public void AddListener(string name, Callback listenerBeingAdded) 116 { 117 OnAdding(name,listenerBeingAdded); 118 //存储这个name 对应的delegate 119 eventDict[name] = (Callback)eventDict[name] + listenerBeingAdded; 120 } 121 122 public static void AddListener<T>(string name,Callback<T> listenerBeingAdded) 123 { 124 OnAdding(name, listenerBeingAdded); 125 eventDict[name] = (Callback<T>)eventDict[name] + listenerBeingAdded; 126 } 127 public static void AddListener<T,U>(string name,Callback<T,U> listenerBeingAdded) 128 { 129 OnAdding(name, listenerBeingAdded); 130 eventDict[name] = (Callback<T, U>)eventDict[name] + listenerBeingAdded; 131 } 132 133 public static void AddListener<T,U,V>(string name,Callback<T,U,V> listenerBeingAdded) 134 { 135 OnAdding(name, listenerBeingAdded); 136 eventDict[name] = (Callback<T, U, V>)eventDict[name] + listenerBeingAdded; 137 } 138 #endregion 139 140 #region RemoveListener 141 static public void RemoveListener(string name, Callback ListenerBeingRemoved) 142 { 143 //移除前检查 144 OnRemoving(name, ListenerBeingRemoved); 145 eventDict[name] = (Callback)eventDict[name] - ListenerBeingRemoved; 146 //移除后检查 147 OnRemoved(name); 148 } 149 150 static public void RemoveListener<T>(string name,Callback<T> ListenerBeingRemoved) 151 { 152 OnRemoving(name, ListenerBeingRemoved); 153 eventDict[name] = (Callback<T>)eventDict[name] - ListenerBeingRemoved; 154 OnRemoved(name); 155 } 156 public static void RemoveListener<T,U>(string name,Callback<T,U>listenerBeingRemoved) 157 { 158 OnRemoving(name, listenerBeingRemoved); 159 eventDict[name] = (Callback<T, U>)eventDict[name] - listenerBeingRemoved; 160 OnRemoved(name); 161 162 } 163 164 public static void RemoveListener<T,U,V>(string name,Callback<T,U,V>listenerBeingRemoved) 165 { 166 OnRemoving(name, listenerBeingRemoved); 167 eventDict[name] = (Callback<T, U, V>)eventDict[name] - listenerBeingRemoved; 168 OnRemoved(name); 169 } 170 #endregion 171 172 #region BroadCast 173 174 public static void BroadCast(string name) 175 { 176 OnBroadcasting(name); 177 178 Delegate d; 179 if(eventDict.TryGetValue(name,out d)) 180 { 181 Callback callback = d as Callback; 182 183 if(callback != null) 184 { 185 callback(); 186 } 187 else 188 { 189 throw CreateBroadcastSignatureException(name); 190 } 191 } 192 } 193 194 public static void BroadCast<T>(string name,T t) 195 { 196 OnBroadcasting(name); 197 198 Delegate d; 199 if(eventDict.TryGetValue(name,out d)) 200 { 201 Callback<T> callback = d as Callback<T>; 202 if(callback != null) 203 { 204 callback(t); 205 } 206 else 207 { 208 throw CreateBroadcastSignatureException(name); 209 } 210 } 211 212 } 213 public static void BroadCast<T,U>(string name,T t,U u) 214 { 215 OnBroadcasting(name); 216 Delegate d; 217 if(eventDict.TryGetValue(name,out d)) 218 { 219 Callback<T, U> callback = d as Callback<T, U>; 220 if(callback != null) 221 { 222 callback(t,u); 223 } 224 else 225 { 226 throw CreateBroadcastSignatureException(name); 227 } 228 } 229 } 230 public static void BroadCast<T,U,V>(string name,T t,U u,V v) 231 { 232 OnBroadcasting(name); 233 Delegate d; 234 if(eventDict.TryGetValue(name,out d)) 235 { 236 Callback<T,U,V> callback = d as Callback<T,U,V>; 237 if(callback != null) 238 { 239 callback(t, u, v); 240 } 241 else 242 { 243 throw CreateBroadcastSignatureException(name); 244 } 245 } 246 } 247 #endregion 248 249 #region Exception 250 public class ListenerException:Exception 251 { 252 public ListenerException(string msg):base(msg) 253 { 254 255 } 256 } 257 258 static public BroadcastException CreateBroadcastSignatureException(string name) 259 { 260 return new BroadcastException(string.Format("Broadcasting message \"{0}\" but listeners have a different signature than the broadcaster.", name)); 261 } 262 263 264 public class BroadcastException :Exception 265 { 266 public BroadcastException(string msg) :base(msg) 267 { 268 269 } 270 } 271 272 #endregion 273 274 } 275 276 277 /// <summary> 278 /// 消息处理帮助类 279 /// </summary> 280 public sealed class MessengerHelper:MonoBehaviour 281 { 282 private void Awake() 283 { 284 DontDestroyOnLoad(gameObject); 285 } 286 287 public void OnLevelWasLoaded(int unUsed) 288 { 289 //每次新level load 的时候,清理以前的message 。 但有些信息需要保留,通用,所以的话, 就必须有永久信息的存储。list 290 Messenger.CleanUp(); 291 } 292 293 294 }
Messenger.cs
时间: 2024-10-18 04:28:31