实现第二种即时的消息机制,写法的话跟第一种几乎一样,只是去掉了Queue并且在消息发出时执行Handler
==============================
1.消息体 AbstractMessage:
public abstract class AbstractMessage
{
public string messageName;
}
同第一种
==============================
2.消息处理函数Handler:
Action<AbstractMessage> handler
同第一种
==============================
3.消息中心MessageCenter在第一种的基础上做一些修改
public class MessageCenter : MonoSingleton<MessageCenter>
{
private Dictionary<string,Action<AbstractMessage>> messageDic = new Dictionary<string,Action<AbstratMessage>>();
//HandleMessage 处理发送的消息
private void HandleMessage(AbstractMessage message)
{
string messageName = message.messageName;
if(messageDic.ContainsKey(messageName))
{
messageDic[messageName](message);
return;
}
Debug.LogError("This message has not registed : " + message.messageName);
}
//RegistMessage 注册消息
public void RegistMessage(string messageName,Action<AbstractMessage> handler)
{
if(messageDic.ContainsKey(messageName))
{
messageDic[messageName] += handler;
return;
}
messageDic[messageName] = handler;
}
//UnRegistMessage 注销消息
public void UnRegistMessage(string messageName,Action<AbstractMessage> handler)
{
if(messageDic.ContainsKey(messageName))
{
if(messageDic[messageName].GetInvocationList().Length > 1)
{
messageDic[messageName] -= handler;
return;
}
messageDic.Remove(messageName);
return;
}
Debug.LogError("This Message Not Registed : " + messageName);
}
//DispatchMessage 发消息
public void DispatchMessage(AbstractMessage message)
{
HandleMessage(message);
}
}
相当于是第一种消息中心的简化,MessageQueue理论上来说,并不需要单例类继承Monobehaviour了,因为不需要Update去实现Loop检测消息功能。但是考虑到可以将两种消息机制合二为一,所以还是继承MonoSingleton。
==============================
4.在对消息机制的实际运用中,只有三种方法需要运用到,也就是MessageCenter里的注册、注销、发送消息。而两种消息机制除了发送消息,其他并没有区别,也就是说,可以给发送消息再添加一个参数,以区分这两种消息种类,我比较偏向于使用枚举来实现。
public enum DispatchMessageType
{
Immediate, //发送即时消息
Queued //发送队列消息
}
public class MessageCenter : MonoSingleton<MessageCenter>
{
private Dictionary<string,Action<AbstractMessage>> messageDic = new Dictionary<string,Action<AbstratMessage>>();
private Queue<AbstractMessage> messageQueue = new Queue<AbstractMessage>();
//Call per frame
private void Update()
{
while(messageQueue.Peek() != null)
{
AbstractMessage message = messageQueue.Dequeue();
HandleMessage(message);
}
}
//HandleMessage 处理发送的消息
private void HandleMessage(AbstractMessage message)
{
string messageName = message.messageName;
if(messageDic.ContainsKey(messageName))
{
messageDic[messageName](message);
return;
}
Debug.LogError("This message has not registed : " + message.messageName);
}
//RegistMessage 注册消息
public void RegistMessage(string messageName,Action<AbstractMessage> handler)
{
if(messageDic.ContainsKey(messageName))
{
messageDic[messageName] += handler;
return;
}
messageDic[messageName] = handler;
}
//UnRegistMessage 注销消息
public void UnRegistMessage(string messageName,Action<AbstractMessage> handler)
{
if(messageDic.ContainsKey(messageName))
{
if(messageDic[messageName].GetInvocationList().Length > 1)
{
messageDic[messageName] -= handler;
return;
}
messageDic.Remove(messageName);
return;
}
Debug.LogError("This Message Not Registed : " + messageName);
}
//DispatchMessage 发消息
public void DispatchMessage(AbstractMessage message,DispatchMessageType typeEnum)
{
switch(typeEnum)
{
case DispatchMessageType.Immediate:
HandleMessage(message);
break;
case DispatchMessageType.Queued:
messageQueue.Enqueue(message);
break;
default:break;
}
}
}
这样就将即时消息和队列消息合二为一,组成了一个完整的消息中心。
==============================
5.最后补充一下,因为现在所使用的Handler都是委托类型,如果将其改为接口,则可以在一个类中实现接口中的函数配合switch以达成统一处理消息的目的。比如定义一个接口IMessageHandler。
public interface IMessageHandler
{
void OnReceiveMessage(AbstractMessage message);
}
然后将MessageCenter里面所有的Action<AbstractMessage>全部替换为IMessageHandler(懒得上代码)
这样的话,假如一个类需要接收消息,继承此接口即可
public class Test : Monobehaviour,IHandleMessage
{
public void OnReceiveMessage(AbstractMessage message)
{
switch(message.messageName)
{
case "message1":
//do something
break;
//case ...
}
}
}
或者再封装一层Monobehaviour,提供注册和注销函数。
public abstract MessageMonobehaviour : MonoBehaviour,IHandler
{
protected virtual void RegistMessage(string MessageName)
{
//由于委托替换为接口,直接用this即可
MessageCenter.Instance.RegistMessage(MessageName,this);
}
protected virtual void UnRegistMessage(string MessageName)
{
//由于委托替换为接口,直接用this即可
MessageCenter.Instance.UnRegistMessage(MessageName,this);
}
//子类重写此方法以处理消息
public virtual void OnReceiveMessage(AbstractMessage message)
{
Debug.Log(this.GetType() + " ReceiveMessage, MessageName : " + message.messageName);
}
}
==============================
没了,消息机制应该就这么多,想到了再补充