先考虑需要实现的基本功能: 在任意一个地方增加一个消息的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