一个类要是想调用另一个类的方法,例如A想调用B的方法。
方式一:引用
最简单的方式是A持有一个B类的引用,即A拥有一个B的成员对象。
方式二:设计模式(中介者模式)
或者A和B同属于一个对象C,通过对象C调用对方(中介者模式),例如QQ群,A和B互相没有对方好友,但是都在一个QQ群C,他们可以在C互相和对方说话。
方式三:静态(通常是单例模式,B是管理类等)
将B中的方法设置为静态方法。
但是项目中,有N多类,A和B完全没有关系,不宜有对方的引用,并且都不是工具类,不宜设置为静态方法。那么此时,我们该如何让A和B建立联系呢?
答案是使用全局事件系统。
提取出来一个可以全局访问的事件列表(字典)
public class EventManager : MonoBehaviour
{
public static Dictionary<EventType, List<Delegate>> EventDic = new Dictionary<EventType, List<Delegate>>();
public delegate void CallBack();
public delegate void CallBack<T>(T parameter);
public static void AddListener(EventType eventType, CallBack callBack)
{
if (EventDic.ContainsKey(eventType))
{
EventDic[eventType].Add(callBack);
}
else
{
EventDic.Add(eventType, new List<Delegate>() {
callBack });
}
}
public static void RemoveListener(EventType eventType, CallBack callBack)
{
if (EventDic.ContainsKey(eventType))
{
CallBack currentCallBack = null;
foreach (var item in EventDic[eventType])
{
currentCallBack = item as CallBack;
if (currentCallBack == callBack)
{
currentCallBack = callBack;
}
}
if (currentCallBack != null)
{
EventDic[eventType].Remove(callBack);
}
if (EventDic[eventType].Count == 0)
{
EventDic.Remove(eventType);
}
}
else
{
throw new Exception("当前系统未注册该事件");
}
}
public static void AddListener<T>(EventType eventType, CallBack<T> callBack)
{
if (EventDic.ContainsKey(eventType))
{
EventDic[eventType].Add(callBack);
}
else
{
EventDic.Add(eventType, new List<Delegate>() {
callBack });
}
}
public static void RemoveListener<T>(EventType eventType, CallBack<T> callBack)
{
if (EventDic.ContainsKey(eventType))
{
CallBack<T> currentCallBack = null;
foreach (var item in EventDic[eventType])
{
currentCallBack = item as CallBack<T>;
if (currentCallBack == callBack)
{
currentCallBack = callBack;
}
}
if (currentCallBack != null)
{
EventDic[eventType].Remove(callBack);
}
if (EventDic[eventType].Count == 0)
{
EventDic.Remove(eventType);
}
}
else
{
throw new Exception("当前系统未注册该事件");
}
}
public static void Dispatch(EventType eventType)
{
if (EventDic.ContainsKey(eventType))
{
CallBack callBack;
foreach (var item in EventDic[eventType])
{
callBack = item as CallBack;
if (callBack != null)
{
callBack();
}
}
}
else
{
throw new Exception("当前事件系统不包含该事件");
}
}
public static void Dispatch<T>(EventType eventType, T parameter)
{
if (EventDic.ContainsKey(eventType))
{
CallBack<T> callBack;
foreach (var item in EventDic[eventType])
{
callBack = item as CallBack<T>;
if (callBack != null)
{
callBack(parameter);
}
}
}
else
{
throw new Exception("当前事件系统不包含该事件");
}
}
}
public class EventData
{
public int money;
}
public enum EventType
{
AddMoney,
AddMoneyWithParameter,
AddMoneyWithEventData,
}
索引是枚举,值是委托类型。
然后A、B将自身需要给外部调用的方法注册进去。
此处拿员工老板举例。
老板提供收钱的方法,员工负责调用。
public class Boss: MonoBehaviour
{
public Button AddListenerButton;
public Button RemoveListenerButton;
void Awake()
{
AddListenerButton.onClick.AddListener(() =>
{
EventManager.AddListener(EventType.AddMoney, GetMoney);
EventManager.AddListener<int>(EventType.AddMoneyWithParameter, GetMoneyWihtPrameter);
EventManager.AddListener<EventData>(EventType.AddMoneyWithEventData, GetmoneyWithEventData);
});
RemoveListenerButton.onClick.AddListener(() =>
{
EventManager.RemoveListener(EventType.AddMoney, GetMoney);
EventManager.RemoveListener<int>(EventType.AddMoneyWithParameter, GetMoneyWihtPrameter);
EventManager.RemoveListener<EventData>(EventType.AddMoneyWithEventData, GetmoneyWithEventData);
});
}
void GetMoney()
{
Debug.Log("收到用户购买的资金,员工真棒");
}
void GetMoneyWihtPrameter(int money)
{
Debug.Log("收到用户购买的资金,员工真棒,收入赚了 " + money);
}
void GetmoneyWithEventData(EventData data)
{
Debug.Log("通过事件数据收到用户购买的资金,员工真棒,收入赚了 " + data.money);
}
}
public class Staff : MonoBehaviour
{
public Button BuyButton;
public Button BuyButtonWithParameter;
public Button BuyButtonWithEventData;
private void Start()
{
BuyButton.onClick.AddListener(() =>
{
EventManager.Dispatch(EventType.AddMoney);
});
BuyButtonWithParameter.onClick.AddListener(() =>
{
EventManager.Dispatch(EventType.AddMoneyWithParameter, 100);
});
BuyButtonWithEventData.onClick.AddListener(() =>
{
EventManager.Dispatch(EventType.AddMoneyWithEventData, new EventData() {
money = 200});
});
}
}
实际效果演示如下:
总结:
全局事件中用到了泛型(调用的时候确定数据类型),父类可以接受所有子类(Delegate可以接收所有子类),重载(注册的方法可以有参数,也可以没有参数)三部分。
有点类似中介者模式,全局事件作为一个中介,向外提供一个事件注册和调用,达到了类与类之间解耦的问题。
Demo