• Unity 消息管理(观察煮模式)


    一、首先定义一份消息号(消息号用来标记发出的每一条消息,接收者通过注册要监听的消息号来监听相应的消息)

    public enum MSG_IDS
    {
        NONE = -1,
        MSG_TEST01 = 100000,
        MSG_TEST02 = 100001,
    }

    二、然后定义一个消息类,作为消息的载体

    public class Notification {
        MSG_IDS id = MSG_IDS.NONE; //消息号
        public MSG_IDS Id{get { return id; }}
        Dictionary<string, object> infos;// 消息内容,消息要传递的具体信息

        public Notification(MSG_IDS id)
        {
            this.id = id;
            infos = new Dictionary<string, object>();
        }
       //消息索引器,用字符串做key(注意key不能重复)
        public object this[string id]
        {
            get {
                if(infos.ContainsKey(id))
                {
                    return infos[id];
                }else
                {
                    Debug.LogError("不存在参数:" + id);
                    return null;
                }
            }
            set {
                if(infos.ContainsKey(id))
                {
                    infos[id] = value;
                }else
                {
                    infos.Add(id, value);
                }
            }
        }
    }

    三、组件ID生成器,这个主要用于标记组件内的事件,以便移除

    public class IDCreator{
        uint curMaxId = 0;
        List<uint> recycleIndex = new List<uint>();
        public uint GetNewID()
        {
            if (recycleIndex.Count > 0)
            {
                uint id = recycleIndex[recycleIndex.Count - 1];
                recycleIndex.RemoveAt(recycleIndex.Count - 1);
                return id;
            }
            if (curMaxId == UInt32.MaxValue)
            {
                Debug.LogError("ID 溢出");
                return curMaxId;
            }
            return curMaxId++;
        }
        public void Recycle(uint id)
        {
            recycleIndex.Add(id);
        }
    }

    四、消息管理器

    public class MsgController{
        public delegate void MsgDel(Notification notify);
        private Dictionary<MSG_IDS, List<MsgDel>> MsgDic;
        private Dictionary<uint, Dictionary<MSG_IDS, MsgDel>> MsgDicMap;
        private static MsgController _instance = null;
        
        public static MsgController Instance
        {
            get
            {
                if(_instance == null)_instance = new MsgController();
                return _instance;
            }
        }

        private static IDCreator _componentID = null;
        /// <summary>
        /// 组件唯一id生成器
        /// </summary>
        public static IDCreator ComponentID
        {
            get
            {
                if (_componentID == null) _componentID = new IDCreator();
                return _componentID;
            }
        }

        /// <summary>
        /// 添加监听
        /// </summary>
        /// <param name="msgId"></param>
        /// <param name="msg"></param>
        public void AddNotification(uint index, MSG_IDS msgId, MsgDel msg)
        {
            try
            {
                if (MsgDic == null)
                {
                    MsgDic = new Dictionary<MSG_IDS, List<MsgDel>>();
                }
                if (MsgDicMap == null)
                {
                    MsgDicMap = new Dictionary<uint, Dictionary<MSG_IDS, MsgDel>>();
                }

                //按消息号保存消息列表
                if (!MsgDic.ContainsKey(msgId))
                {
                    List<MsgDel> list = new List<MsgDel>();
                    MsgDic.Add(msgId, list);
                }
                MsgDic[msgId].Add(msg);
                //按id索引保存消息列表
                if (!MsgDicMap.ContainsKey(index))
                {
                    Dictionary<MSG_IDS, MsgDel> map = new Dictionary<MSG_IDS, MsgDel>();
                    MsgDicMap.Add(index, map);
                }
                MsgDicMap[index].Add(msgId, msg);
            }catch(Exception e)
            { throw (e); }
        }

        /// <summary>
        /// 移除一个组件上的所有事件
        /// </summary>
        /// <param name="index"></param>
        public void RemoveAllNotification(uint index)
        {
            if(MsgDicMap.ContainsKey(index))
            {
                foreach (var map in MsgDicMap[index])
                {
                    RemoveNotification(map.Key, map.Value);
                }
            MsgDicMap.Remove(index);
                _componentID.Recycle(index);//回收id以便重复利用
            }
        }

        /// <summary>
        /// 移除某个id对应的监听事件
        /// </summary>
        /// <param name="msgId"></param>
        /// <param name="msg"></param>
        public void RemoveNotification(MSG_IDS msgId, MsgDel msg)
        {
            try
            {
                MsgDic[msgId].Remove(msg);
            }catch(Exception e)
            {
                Debug.LogError("找不到消息:" + msgId);
                throw(e);
            }
        }

        /// <summary>
        /// 发送通知
        /// </summary>
        /// <param name="notify"></param>
        public void SendMsg(Notification notify)
        {
            try
            {
                if (MsgDic.ContainsKey(notify.Id))
                {
                    List<MsgDel> msgs = MsgDic[notify.Id];
                    for (int i = 0; i < msgs.Count; i++)
                    {
                        msgs[i](notify);
                    }
                }
            }catch(Exception e)
            { throw (e); }
        }

    四、发送、接收消息实例

    public class Sender : MonoBehaviour {
       int n = 0;
    public void Btn1() { Notification notify = new Notification(MSG_IDS.MSG_TEST01);
            notify["text"] = "第" + (++n) + "次 string ";
            MsgController.Instance.SendMsg(notify); }
      int m = 0;
    public void Btn2() { Notification notify = new Notification(MSG_IDS.MSG_TEST02);
            notify["value"] = ++m;
            MsgController.Instance.SendMsg(notify); }
    }
    public class Listener01 : MonoBehaviour
    {
        uint eventIndex = 0;
        void OnEnable()
        {
            eventIndex = MsgController.ComponentID.GetNewID();//获取一个组件id,这个id的意义在于,当一个组件上加了很多监听时,不需要一个个移除。一个个移除很麻烦,也很容易出错
            MsgController.Instance.AddNotification(eventIndex, MSG_IDS.MSG_TEST01, MsgListener01);
            MsgController.Instance.AddNotification(eventIndex, MSG_IDS.MSG_TEST02, MsgListener02);
        }

        void OnDisable()
        {
            MsgController.Instance.RemoveAllNotification(eventIndex);//移除所有组件id为eventIndex的监听(并不关心eventIndex的值是多少
        }

        public void MsgListener01(Notification notify)
        {
            string text = (string)notify["text"];
            Debug.LogError(transform.name + " " + text);
        }

        public void MsgListener02(Notification notify)
        {
            int v = (int)notify["value"];
            Debug.LogError(transform.name + " " + v.ToString());
        }
    }
  • 相关阅读:
    Packetbeat协议扩展开发教程(2)
    C语言函数的定义和使用(2)
    C程序的函数说明使用和特点说明第一节
    C 利用移位运算符 把十进制转换成二进制
    while循环实现十进制转二进制
    C位运算符的使用
    C语言for 循环 9*9 实现九九乘法表
    C语言实现金字塔
    C语言实现的简单银行存取款程序 请输入如下数字命令
    C语言中一个字符对应一个ascii码;占一个1个字节8个二进制位;存到内存中也是用ascii的十进制的二进制表示
  • 原文地址:https://www.cnblogs.com/yougoo/p/8850085.html
Copyright © 2020-2023  润新知