如果在代码中出现耦合,想要解除耦合的情况,就可以使用事件中心的代码。
事件中心的工作原理
我们假设你的小区里面有一个快递驿站,
订阅事件(存快递):
小明说:“驿站老板,如果有我的包裹(某个事件发生),请打电话通知我”
小红说:“驿站老板,如果有我的快递(另外一个事件),请发短信通知我”
触发事件(快递到了):
当驿站收到一个包裹(比如“玩家死亡”事件),老板会立刻通知所有订阅了这个包裹的人(小明、小红等)。
好处:
小明和小红不用天天盯着快递员(不用直接互相调用代码)
驿站集中管理所有包裹(统一管理事件)
随时可以取消订阅(“老板,以后不用通知我了!”)
一个简单的事件中心代码
通过上面的例子来模拟事件中心。
我们先制作一个快递驿站(创建事件中心)
快递驿站需要做什么工作?存放事件、通知玩家?
怎么存放事件?通过委托可以存放事件。
订阅事件?玩家注册事件(告诉事件中心,如果有我的快递,请通知我)
触发事件?事件中心检测到事件触发,会通知订阅该事件的玩家
public class EventCenter : MonoBehaviour {
// 为什么是单例的?因为玩家要订阅事件
public static EventCenter Instance;
public Action<string> OnEvent; // 委托:可以存储多个方法
void Awake() => Instance = this;
// 触发事件:通知订阅的人
public void TriggerEvent(string eventName) => OnEvent?.Invoke(eventName);
}
// 订阅者
public void Start(){
// 告诉:事件中心,我的快递到了记得通知我哦
EventCenter.Instance.OnEvent += (info)=>{
// 快递到了,执行下面的逻辑
};
}
// 触发者
void Update() {
// 模拟快递到了情况
if (Input.GetKeyDown(KeyCode.Space)) {
// 通知事件执行,这个快递到了
EventCenter.Instance.TriggerEvent("小明的快递");
}
}
应用场景
1. 泛型版本的事件中心
想象事件中心是一个智能快递柜,泛型事件就是可以存放各种尺寸包裹的储物格。
// 我们设计一个智能快递柜
// 第一个参数是:每个快递柜门的编号
// 第二个参数是:包裹容器(就是这个柜门可以放任意大小的包裹)任意委托。然而,在从字典中检索这些委托并调用之前,你需要将它们转换回原始的委托类型
private Dictionary<string, Delegate> genericEventDict = new Dictionary<string, Delegate>();
接下来我们可以寄存包裹
public void AddListener<T>(string eventName, Action<T> action)
{
// 判断快递门编号为eventName是否已经寄存过了这个包裹
if (genericEventDict.ContainsKey(eventName))
{
// 如果有,那么在旧包裹中继续塞一个新包裹
genericEventDict[eventName] = Delegate.Combine(genericEventDict[eventName], action);
}
else
{
// 如果没有,直接塞进去
genericEventDict.Add(eventName, action);
}
}
领取包裹
public void TriggerEvent<T>(string eventName, T arg)
{
// 查找包裹,并验证是否是Action<T>类型的
if (genericEventDict.TryGetValue(eventName, out Delegate del))
{
// 取出包裹,交给收件人
(del as Action<T>)?.Invoke(arg);
}
}
评论区