概述
该模式大概是这样的 根据功能划分不同的模块,例如数据模块,音频模块,战斗模块,界面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);
最后
以上就是儒雅云朵为你收集整理的unity 简单的 中介者模式架构的全部内容,希望文章能够帮你解决unity 简单的 中介者模式架构所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复