unity自带消息通信功能SendMessage效率比较低(当场景中的对象和脚本组件比较多的时候),在帧里面调用更是灾难的.
试了c#的各种delegate, invoke,效果不好.
最终通过C#反射的方式写了一个订阅广播消息系统.下面讲解一下原理
1.反射:
看这里 https://www.cnblogs.com/Stephenchao/p/4481995.html
2.观察者模式:
看这里 https://www.cnblogs.com/zhili/p/ObserverPattern.html
运行流程
1.通过反射的方式获取到对象的MethodInfo
2.将对象和MethodInfo封装成observer整洁点,打包到list中,再放到一个Dictionary中备用
3.发送消息的时候从Dictionary获取到observer列表,反射调用即可,相信Dictionary的查询效率应该很高
在几个小项目里面试了一下,效果还不错,对于不怎么使用puremvc和ECS,喜欢简单的同学来说还是比较适合的,直接上代码吧
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
public class MiniBroadCast {
public static MiniBroadCast Instance = new MiniBroadCast();
private Dictionary<string, List<Observer>> m_method_info = new Dictionary<string, List<Observer>>();
/**
* 注册观察者
*/
public void registListener(string key,string method_name,object instance)
{
if (!m_method_info.ContainsKey(key))
{
m_method_info[key] = new List<Observer>();
}
MethodInfo method = instance.GetType().GetMethod(method_name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
Observer _observer = new Observer();
_observer.method = method;
_observer.instance = instance;
m_method_info[key].Add(_observer);
//Debug.Log("regist observer success: instance:" + instance + " method:" + method);
}
/**
* 注册观察者
* 静态
*/
public void registListener(string key, string method_name, Type type)
{
if (!m_method_info.ContainsKey(key))
{
m_method_info[key] = new List<Observer>();
}
MethodInfo method = type.GetMethod(method_name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
Observer _observer = new Observer();
_observer.method = method;
_observer.instance = null;
m_method_info[key].Add(_observer);
}
/**
* p_params:不定参数
*/
public void breadcast(string key,params object[] p_params)
{
//Debug.Log(key);
if (!this.m_method_info.ContainsKey(key))
{
Debug.LogWarning("observer not find");
return;
}
//反射调用(包括静态方法)
List<Observer> _list = new List<Observer>();
//深度复制一份,避免在反射执行过程中删除观察者出现错误
foreach (Observer o in this.m_method_info[key]){
_list.Add(o);
}
foreach (Observer o in _list)
{
o.method.Invoke(o.instance, p_params);
}
}
public void removeListener(string key, string method_name, object instance)
{
if (!m_method_info.ContainsKey(key))
return;
List<Observer> _list= this.m_method_info[key];
for (int i = _list.Count-1; i>=0; i--)
{
if (_list[i].instance == instance && _list[i].method.Name == method_name)
{
_list.RemoveAt(i);
Debug.Log("observer remove success!");
}
}
if (_list.Count == 0)
this.m_method_info.Remove(key);
}
public void cleanAll()
{
m_method_info = new Dictionary<string, List<Observer>>();
}
private class Observer
{
public object instance;
public MethodInfo method;
}
}
使用方法很简单
1.直接放到项目下面
2.MiniBroadCast.Instance.registListener订阅消息
3. MiniBroadCast.Instance.breadcast广播消息
4. MiniBroadCast.Instance.removeListener取消订阅
5. MiniBroadCast.Instance.cleanAll清除所有订阅
github地址:
https://github.com/baixin1228/unity-breadcast-framwork
后续还会放出Attribute版本的,用法上面更加简易,不需要主动订阅