unity 簡單的 中介者模式架構

該模式大概是這樣的  根據功能劃分不同的模塊,例如數據模塊,音頻模塊,戰鬥模塊,界面UI模塊等,每個模塊有自己單獨的管理器,該管理器實現單例,並由中介者(消息處理器)訪問,而各個模塊之間的互動不在是直接調用,而是通過創建消息體,有消息處理器分發到 接收方,來實現通訊,好處是可以讓多人開發時效率大大提高,也可以讓代碼更加穩定,健康。

消息處理器 即中介者,負責處理各個模塊發來的消息,並進行分發。爲了進行區分模塊,定義了模塊id,根據該id去找到對應模塊的管理器 ,然後由該管理器去處理消息,或者接着分發給下邊的分部。

 同時爲了節省性能,考慮到會使用多個消息,而且數量龐大,就接入對象池,這裏是模擬的一個對象池,並沒有接入真正的對象池, 模塊發消息前要先在中介者哪裏拿到消息體。



//mgrID 模塊ID
public enum MgrID
{
    None = 0,
    GameManager = 1,//遊戲控制器

    UIManager = MsgCenter.msgSpan * 1,//UI模塊
    AssetsManager = MsgCenter.msgSpan * 2,//資源模塊
    AudioManager = MsgCenter.msgSpan * 4,//音頻模塊
    ObjectPoolManager = MsgCenter.msgSpan * 5,//對象池模塊
    SceneManager = MsgCenter.msgSpan * 6,//場景管理模塊
    NetWorkManager = MsgCenter.msgSpan * 7,//網絡管理
    GameDataManager = MsgCenter.msgSpan * 8,//遊戲數據管理
    FightManager = MsgCenter.msgSpan * 10,//戰鬥管理
}

//消息處理中心
public class MsgCenter : MonoBehaviour
{
    private static MsgCenter instance;
    public static MsgCenter Instance
    {
        get
        {
            return instance;
        }
    }

    public const int msgSpan = 100;// 消息模塊間隔

    private Dictionary<string, Queue<MsgBase>> msgpool;//消息池
    private List<MsgBase> activePool;//活躍狀態的消息體
    void Awake()
    {
        instance = this;
        msgpool = new Dictionary<string, Queue<MsgBase>>();
        activePool = new List<MsgBase>();
    }
    #region  消息獲取
    /// <summary>
    /// 獲取無數據消息
    /// </summary>
    /// <param name="msgid"></param>
    /// <returns></returns>
    public MsgBase GetMsg(ushort msgid)
    {
        MsgBase msg;
        Queue<MsgBase> queue;
        if (msgpool.TryGetValue("None", out queue))
        {
            if (queue.Count > 0)
            {
                msg = queue.Dequeue();
                msg.HasRecyle = false;
            }
            else
            {
                //實例化一個新的
                msg = new MsgBase();
                msg.SetbaseKey("None");
            }
        }
        else
        {
            queue = new Queue<MsgBase>();
            msgpool.Add("None", queue);
            msg = new MsgBase();
            msg.SetbaseKey("None");
        }
        msg.msgID = msgid;
        activePool.Add(msg);
        //Debuger.Log("申請消息: 無參", Color.yellow);
        return msg;
    }
    /// <summary>
    /// 獲取單類型消息
    /// </summary>
    /// <typeparam name="T">傳遞的數據類型</typeparam>
    /// <param name="t">傳遞的數據</param>
    /// <returns></returns>
    public MsgBase GetMsgOne<T>(T t)
    {
        MsgOne<T> msg;
        Queue<MsgBase> queue;
        string key = t.GetType().ToString();
        //Debuger.Log("消息數據類型:" + key);
        if (msgpool.TryGetValue(key, out queue))
        {
            //Debuger.Log("當前類型的消息剩餘:" + queue.Count);
            if (queue.Count > 0)
            {
                msg = queue.Dequeue() as MsgOne<T>;
                msg.HasRecyle = false;
            }
            else
            {
                //實例化一個新的
                msg = new MsgOne<T>();
            }
        }
        else
        {
            //新建一個池子
            queue = new Queue<MsgBase>();
            msgpool.Add(key, queue);
            //實例化新的消息
            msg = new MsgOne<T>();
        }
        msg.SetData(t);
        activePool.Add(msg);
        //Debuger.Log("申請消息: 單參數:"+msg .key, Color.yellow);
        return msg;
    }
    public MsgBase GetMsgOne<T>(List<T> list)
    {
        MsgOne<T> msg;
        Queue<MsgBase> queue;
        string key = typeof(T).ToString();
        //Debuger.Log("消息數據類型:" + key);
        if (msgpool.TryGetValue(key, out queue))
        {
            //Debuger.Log("當前類型的消息剩餘:" + queue.Count);
            if (queue.Count > 0)
            {
                msg = queue.Dequeue() as MsgOne<T>;
                msg.HasRecyle = false;
            }
            else
            {
                //實例化一個新的
                msg = new MsgOne<T>();
            }
        }
        else
        {
            //新建一個池子
            queue = new Queue<MsgBase>();
            msgpool.Add(key, queue);
            //實例化新的消息
            msg = new MsgOne<T>();
        }
        msg.SetData(list);
        activePool.Add(msg);
       // Debuger.Log("申請消息: 多參數:" + msg.key, Color.yellow);

        return msg;

    }
    /// <summary>
    /// 獲取多類型消息
    /// </summary>
    /// <typeparam name="T">類型1</typeparam>
    /// <typeparam name="T2">類型2</typeparam>
    /// <param name="t">類型1數據</param>
    /// <param name="t2">類型2數據</param>
    /// <returns></returns>
    public MsgBase GetMsgMore<T, T2>(T t, T2 t2)
    {
        MsgMore<T, T2> msg;
        Queue<MsgBase> que;
        string key = t.GetType().ToString() + "_" + t2.GetType().ToString();
        //Debuger.Log("獲取的消息key:" + key, Color.green);

        if (msgpool.TryGetValue(key, out que))
        {
            //Debuger.Log("當前類型的消息剩餘:" + que.Count);
            if (que.Count > 0)//池中還有沒使用的,就拿出來
            {
                msg = que.Dequeue() as MsgMore<T, T2>;
                msg.HasRecyle = false;
            }
            else
            {
                msg = new MsgMore<T, T2>();
            }
        }
        else
        {
            //Debuger.Log(activePool.Count.ToString(), Color.yellow);
            que = new Queue<MsgBase>();
            msgpool.Add(key, que);
            msg = new MsgMore<T, T2>();
        }
        msg.SetData(t, t2);
        activePool.Add(msg);
        //Debuger.Log("申請消息: 多參數:" + msg.key, Color.yellow);
        return msg;
    }
    public MsgBase GetMsgMore<T, T2>(List<T> t, List<T2> t2)
    {
        MsgMore<T, T2> msg;
        Queue<MsgBase> que;
        string key = t.GetType().ToString() + "_" + t2.GetType().ToString();
        //Debuger.Log("獲取的消息key:" + key, Color.green);

        if (msgpool.TryGetValue(key, out que))
        {
            //Debuger.Log("當前類型的消息剩餘:" + que.Count);
            if (que.Count > 0)//池中還有沒使用的,就拿出來
            {
                msg = que.Dequeue() as MsgMore<T, T2>;
                msg.HasRecyle = false;
            }
            else
            {
                msg = new MsgMore<T, T2>();
            }
        }
        else
        {
            //Debuger.Log(activePool.Count.ToString(), Color.yellow);
            que = new Queue<MsgBase>();
            msgpool.Add(key, que);
            msg = new MsgMore<T, T2>();
        }
        msg.SetData(t, t2);
        activePool.Add(msg);
        //Debuger.Log("申請消息: 多參數:" + msg.key, Color.yellow);
        return msg;
    }

    #endregion

    public void Clear()
    {
        //清理消息池
        while (activePool.Count > 0)
        {
            activePool[0].Recyle();
        }
    }
    //處理消息
    public void ProcessMsg(MsgBase msg)
    {
        switch (msg.manager)
        {
            case MgrID.None:
                break;
            case MgrID.GameManager:
                GameManager.instance.ProcessMsg(msg);
                break;
            case MgrID.UIManager:
                UIManager.instance.ProcessMsg(msg);
                break;
            case MgrID.AssetsManager:
                AssetsManager.instance.ProcessMsg(msg);
                break;
            case MgrID.AudioManager:
                AudioMgr.instance.ProcessMsg(msg);
                break;
            case MgrID.ObjectPoolManager:
                ObjectPoolMgr.instance.ProcessMsg(msg);
                break;
            case MgrID.SceneManager:
                SceneController.instance.ProcessMsg(msg);
                break;
            case MgrID.GameDataManager:
                GameDataManager.instance.ProcessMsg(msg);
                break;
            case MgrID.FightManager:
                FightController.Instance.ProcessMsg(msg);
                break;
            default:
                break;
        }
    }
    //回收消息
    public void Recyle(MsgBase msg)
    {
        //Debuger.Log("回收消息:id :" + msg.msgID + " key:" + msg.key, Color.yellow);
        Queue<MsgBase > msgs;
        if (msgpool .TryGetValue (msg .key ,out msgs))
        {
            msgs.Enqueue(msg);
        }else
        {
            msgs = new Queue<MsgBase>();
            msgs.Enqueue(msg);
            msgpool.Add(msg .key,msgs);
        }
        
        activePool.Remove(msg);
    }
}

消息體 存儲本次要發送的數據,這裏做成泛型,支持但數據和多數據。並且支持多類型數據的傳輸。將它抽象是爲了在只需要傳遞消息不需要傳遞數據時剩下空間。直接傳遞基類(包含管理器id,消息id)可咦根據項目實際需求擴展


/// <summary>
/// 消息基類 擴展的消息要繼承自此  不傳遞數據
/// </summary>
public class MsgBase
{
    public string key;//存入池中的key
    public MgrID manager;//附屬的模塊管理器
    public ushort   msgID;//具體的msgID,接受者要轉換到自己的模塊ID
    public bool AutoRecyle = true;//是否自動回收,如果設置爲false,接收方在該消息使用完後不會回收
    public bool HasRecyle=false ;//是否已經回收
    public MsgBase()
    {
    }
    public void SetbaseKey(string str)
    {
        key = str;
    }
    //消息回收
    public virtual  void Recyle()
    {
        if (!AutoRecyle) return;
        // 回收對象池
        MsgCenter.Instance.Recyle(this);
        HasRecyle = true;
    }
}

//----------------------------------------使用泛型的好處:相當於一個容器,不需要 知道具體的類型,只作爲存儲和傳遞使用,不用再爲每個類型單獨定義-------------------------------------
/// <summary>
/// 帶單個類型數據 
/// </summary>
/// <typeparam name="T"></typeparam>
public class MsgOne<T> : MsgBase
{
    public List<T> valuelist;
    /// <summary>
    /// 置入數據
    /// </summary>
    /// <param name="t"></param>
    public void SetData(T t)
    {
        HasRecyle = false;
        if (valuelist == null)
        {
            valuelist = new List<T>();
        }
        valuelist.Add(t);
        if (string.IsNullOrEmpty(key))
            SetKey(t.GetType().ToString());
    }
    public void SetData(List <T> list)
    {
        if (valuelist == null)
        {
            valuelist = new List<T>();
        }
        valuelist = list;
        HasRecyle = false;
        if (string.IsNullOrEmpty(key))
            SetKey(typeof(T).ToString());
    }
    private  void SetKey(string str)
    {
        key = str;
    }
    public override void Recyle()
    {
        valuelist.Clear();
        //Debuger.Log("key :" + key );
        base.Recyle();
    }
}
/// <summary>
/// 多個類型的數據
/// </summary>
/// <typeparam name="T1"></typeparam>
/// <typeparam name="T2"></typeparam>
public class MsgMore<T1,T2>:MsgBase
{
    public List<T1> T1list;
    public List <T2 >T2list;

    public void SetData(T1 t1,T2 t2)
    {
        HasRecyle = false;
        if (T1list == null)
        {
            T1list = new List<T1>();
            T2list = new List<T2>();
        }
        T1list.Add(t1);
        T2list.Add(t2);
        if (string.IsNullOrEmpty(key))
            SetKey(t1.GetType().ToString() + "_" + t2.GetType().ToString());
    }
    public void SetData(List<T1>t1s,List <T2 >t2s)
    {
        HasRecyle = false;
        T1list = t1s;
        T2list = t2s;
        if (string.IsNullOrEmpty(key))
            SetKey(typeof(T1).ToString() + "_" + typeof(T2).ToString());
    }
    public  void SetKey(string str)
    {
        key = str;
        //Debuger.Log("消息key:" + str);
    }
    public override void Recyle()
    {
        T1list.Clear();
        T2list.Clear();
        base.Recyle();
    }
}

模塊管理器 負責處理模塊內部所有的消息的分發,和傳遞,內部的部分如果有接受消息和發送的需求都要註冊到管理器內,這樣當管理器接收到對應的消息,才能找到接受者。

//模塊管理器基類
public class MgrBase : MonoBehaviour
{

    //消息節點 用於存儲消息
    public class MsgNode
    {
        public MsgNode nextNode;//下一節點
        public PartBase part;//當前接受的對象
        public MsgNode()
        {

        }
        public MsgNode(PartBase part)
        {
            this.part = part;
            nextNode = null;
        }
        public MsgNode(PartBase part, MsgNode next)
        {
            this.part = part;
            nextNode = next;
        }
    }

    public MgrID ID;//管理器ID
    protected Dictionary<ushort , MsgNode> dic_MsgNode;//該模塊的消息池 id : node 

    void Awake()
    {
        dic_MsgNode = new Dictionary<ushort, MsgNode>();
        OnAwake();
    }
    public virtual void OnAwake() { }



    //註冊消息
    public void RegisterMsg(ushort msgID,PartBase part)
    {
        if(dic_MsgNode .ContainsKey (msgID))
        {
            //拿到末尾的
            MsgNode node=dic_MsgNode [msgID ];
            while(node .nextNode !=null)
            {
                node = node.nextNode;
            }
            //存儲
            node.nextNode = new MsgNode(part);
        }
       else
        {
            dic_MsgNode.Add(msgID, new MsgNode(part));
        }
        //Debug.Log("zuce:" + msgID);
    }
    //反註冊消息
    public void UnRegisterMsg(ushort msgID,PartBase part)
    {
        //Debuger.Log("反註冊:L" + part .gameObject .name);
        MsgNode cur_Node,lastNode;
        if (dic_MsgNode .TryGetValue (msgID,out cur_Node ))//此時拿到的是根節點
        {
            if (cur_Node.part == part)//移除的是根節點
            {
                if (cur_Node.nextNode != null)
                    dic_MsgNode[msgID] = cur_Node.nextNode;//更換頭結點
                else
                    dic_MsgNode.Remove(msgID);//清楚該消息的監聽
            }
            else
            {
                lastNode = cur_Node;//要刪除節點的上一個節點
                while (cur_Node.part != part)
                {
                    lastNode = cur_Node;//要刪除節點的上一個節點
                    cur_Node = cur_Node.nextNode;
                }
                //將當前節點的上一個的下級節點指向當前節點的下級節點
                if (cur_Node.nextNode != null)
                {
                    lastNode.nextNode = cur_Node.nextNode;//吧當前節點移除掉
                }
                else
                {
                    //說明當前節點爲尾節點
                    lastNode.nextNode = null;
                }
            }
        }
        else
        {
            Debuger.Log("未註冊該消息:" + msgID, Color.red);
        }
    }
    //清空
    public void Clear()
    {
        dic_MsgNode.Clear();
        dic_MsgNode = new Dictionary<ushort, MsgNode>();
    }
    /// <summary>
    /// 發送消息
    /// </summary>
    public virtual void Send(MsgBase msg)
    {
        if (msg .HasRecyle)
        {
            Debuger.Log("當前消息已經被回收,請確認發送的消息!",Color .red);
            return;
        }
        MsgCenter.Instance.ProcessMsg(msg);
    }
    /// <summary>
    /// 
    /// </summary>
    public virtual void ProcessMsg(MsgBase msg)
    {

    }
    /// <summary>
    /// 分發模塊內部消息
    /// </summary>
    public void Notify(MsgBase msg)
    {
        ushort id = msg.msgID;
        if (dic_MsgNode.ContainsKey(id))
        {
            MsgNode node = dic_MsgNode[id];
            node.part.ProcessMsg(msg);
            while (node.nextNode != null&& !msg .HasRecyle )
            {
                node = node.nextNode;
                node.part.ProcessMsg(msg);
            }
        }
        else
        {
            Debuger.LogError("該消息尚未註冊!!" + id);
        }
    }
}

 模塊分部基類 只有繼承或者掛載了該類的才能進行數據接受分發,當然,要在初始化的時候註冊自己到所在模塊管理器內,然後將要監聽的消息id進行實例化並配置


/// <summary>
/// 所有涉及到消息接受處理的基類
/// </summary>
public  class PartBase : MonoBehaviour
{
    public MgrBase manager;//該模塊管理器
    public ushort[] msgIDs;
    private bool hasrecle;
    /// <summary>
    /// 發送消息
    /// </summary>
    public virtual void Send(MsgBase msg)
    {
        if (msg.HasRecyle)
        {
            Debuger.Log("當前消息已經被回收,請確認發送的消息!", Color.red);
            return;
        }
        if (manager == null)
        {
            Debuger.Log("請先指定模塊管理器!!"+gameObject .name, Color.red);
            return;
        }
        if (manager.ID == msg.manager)
            manager.ProcessMsg(msg);//內部通信,管理器直接處理
        else
        {
            manager.Send(msg);//外部消息由管理器統一傳遞
        }
    }
    /// <summary>
    /// 處理消息 
    /// </summary>
    public virtual  void ProcessMsg(MsgBase msg)
    {
    }

    //註冊消息
    public void RegisteSelf(MgrBase mgr)
    {
        manager = mgr;
        if (msgIDs ==null ||msgIDs .Length == 0)
        {
            Debuger .LogWarning("注意:該部分未註冊任何消息,請確認!"+gameObject .name);
        }else
        {
            if(manager ==null)
            {
                Debuger.LogError("請先指定模塊管理器!!");
                return;
            }
            for (int i = 0; i < msgIDs .Length ; i++)
            {
                manager.RegisterMsg(msgIDs[i], this);
            }
        }
    }
    //反註冊消息
    public void UnRegistSelf()
    {
        if (hasrecle) return;
        hasrecle = true;
        if (msgIDs == null || msgIDs.Length == 0)
        {
            Debuger.LogWarning("注意:該部分未註冊任何消息,請確認!" + gameObject.name);
        }
        else
        {
            if (manager == null)
            {
                Debuger.LogError("請先指定模塊管理器!!"+gameObject .name);
                return;
            }
            for (int i = 0; i < msgIDs.Length; i++)
            {
                manager.UnRegisterMsg(msgIDs[i], this);
                //Debuger.Log("反註冊消息:"+msgIDs [i],Color .red);
            }
        }
    }
    void OnDestroy()
    {
        UnRegistSelf();
    }
}

 

舉個例子:

  MsgOne<string> sendmsg = MsgCenter.Instance.GetMsgOne<string>(Showplayer.freshReadyCards[index].info.Name) as MsgOne<string>;
        sendmsg.manager = MgrID.AudioManager;
        sendmsg.msgID = (ushort)AudioMsgID.PlayHeroSay;
        Send(sendmsg);

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章