Unity3D 消息框架设计

抄自:http://wiki.unity3d.com/index.php/Advanced_CSharp_Messenger

附上自己的一些理解:

先考虑需要实现的基本功能: 在任意一个地方增加一个消息的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
原文地址:https://www.cnblogs.com/binpan/p/4290891.html