zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    js正则还原和转义特殊字符
    element表格鼠标悬浮上带有点击事件的变红-:row-class-name
    elemen-table表格数据转换-formatter属性
    SVN的安装及汉化的
    element中关于input框
    VUE之兄弟组件 $emit和$on、$bus的用法
    关于element表单校验(二)
    关于element表单校验(一)
    element表格里数据处理
    各类手册收藏整理
  • 原文地址:https://www.cnblogs.com/binpan/p/4290891.html
Copyright © 2011-2022 走看看