浅析消息系统

一、消息系统?

基于观察者模式的一种基础库,核心思想是能够跨平台、跨语言的。

既然是消息系统,肯定有一个系统管理者MessageManager,这个类是单例的,便于业务逻辑脚本的调用。那么它负责什么事情呢?消息的注册和反注册,消息的发送。那么谁负责接收消息呢?业务逻辑脚本(调用管理器的注册方法时绑定事件类型Key和接收到消息后执行的事件回调CallBack),当接收到消息广播后执行绑定的事件。

MessageManager:
1.注册:AddListener
2.反注册:RemoveListener
3.发送消息:Notify

Buisiness Logic:
1.接收消息:msgManager.AddLister(key, callback)

至此,我们明白了:
1.消息要注册,才能够接受。 我们通过一个字符串作为key来区分不同的消息类型,在实际的工作中,可以通过定义枚举代表业务使代码更加清晰易懂,避免过多的自定义字符串分散在脚本里。
2.消息要反注册,才是一个完整的闭环。 拿Unity举栗子:我们在场景SceneA注册了(生命周期Awake或者Start)消息OpenUI,但是没有在OnDestroy里面反注册,那么在跳转到场景B后, 如果再次调用OpenUI(这种比较通用的key),因为消息没有反注册,仍会存在我们的对象池里面,就会导致取用的是上一个场景的事件,极易触发MissReference错误。


最基础的消息结构应该是这样的:
浅析消息系统_第1张图片
没有返回值,也没有参数,函数自身就处理了业务。
作为消息类型的key必须存在;统一类型消息释放后要回归到我们的对象池中,下一次注册时:如果有同类型的则直接分配;没有再new一个(朴实无华的池思想)。

我们在基础消息接口上延伸出多参数的消息接口,就像下面定义委托一样。

那么我们怎么把业务逻辑传递给管理者呢?用委托
关于收发消息的接口,其参数的个数理论上应该是不限制的,我们可以定义一组委托,例如这样:
浅析消息系统_第2张图片
用V代表返回值为void,后面的数字代表参数的个数。你可以很简单的对其进行扩展,以适用组织需求或个人研发。

ps:为什么要用System的delegate而不是采用UnityAction呢,因为后者引擎只定义到了V4级别,为了我们的扩展性和可能出现的高级别情况,我们还是使用delegate来实现。
浅析消息系统_第3张图片
我们需要IMessageSender用于消息的发送:
浅析消息系统_第4张图片
IMessageReceiver用于消息的增加和移除:
浅析消息系统_第5张图片
最后,它们的实现类MessageSender和MessageReceiver,会各有一份实例保存在管理类中,提供给外部调用。MessageManager的Nofity广播函数就是Sender的SendMessage,AddListener就是Receiver的AddDelegate,RemoveListener就是Receiver的RemoveDelegate。

至此,我们明白了:
1.定义最基础的消息接口:仅包含一个key值和释放的方法,在其上做扩展。
2.定义一组可扩展参数和返回值的委托,用于事件的定义和逻辑的调用。
3.通过Sender、Receiver汇集到管理类统一提供给外部调用的方式,使代码逻辑更通畅。


委托调用的情况:有些实现是通过V0~V7类型的识别,通过is转换再进行调用。我们不这么做。

        public void SendMessage(IMessage iMessage)
        {
            if (NeedHandle.ContainsKey(iMessage.key))
            {
                NeedHandle[iMessage.key].DynamicInvoke();
            }
            else
            {
                holder.MessageNotHandled?.Invoke(iMessage);
            }
        }

如果是定义了的消息类型,从字典获取其Delegate然后执行;如果是未定义的,且不在消息队列,我们用一个额外的Action去承接然后去Invoke。

上述代码中holder的定义如下:

namespace UnityFramework {
    public class MessageHolder
    {
        public Action MessageNotHandled;
        public Dictionary NeedHandle = new Dictionary();
    }
}

Holder的实例会在生成之后传入Sender和Receiver,管理类的私有构造会创建实例,持有它们。

对象池的实现代码:https://blog.csdn.net/itsxwz/article/details/117388308
ps:移除了之前写的一篇Unity之对象池实现,里面业务逻辑太多了,代码也不完整。

二、消息系统。

请自行取用学习:
https://github.com/86K/MessageSystem


2021.06.01 ADD
浅析消息系统_第6张图片

你可能感兴趣的:(Frameworks,消息系统)