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);

 

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