您现在的位置是:首页 >学无止境 >[Unity] No.3 EventManager事件管理 与 观察者模式网站首页学无止境
[Unity] No.3 EventManager事件管理 与 观察者模式
EventManager事件管理
前文讲到了InputManager,在其后需要一个事件的管理者用于调度任务的执行,包括:
①查看发生了什么事;
②出事后看看都需要通知谁干什么事;
以上两个内容就对应了EventManager中关键的监听和回调,而在讲EventManager之前还需要知道,它是符合观察者这一模式的。
1. 观察者模式
此处不会像第一篇文章那样子给出观察者的设计模式,因为后续会给出EventManager的一个样例代码,会更容易理解。只需知道的是,观察者模式是一对多的关系,多个观察者对象会同时监听一个主题对象,当主题对象的状态变化时,各个观察者会根据这一变化做出对应的行为。
举一个简单的例子,学生们(观察者)在教室上课,当下课铃响了(主题对象状态改变),各个学生听到后会去完成自己课间需要做的事情,如:上厕所、打水、给对象发消息等等。
注意:下课铃就是上一篇文章中提到的InputManager发来的!
2. 回调函数
回调是一个过程,当一个函数被当作参数传入另一个目标函数,目标函数执行完后去执行被传入的这个函数这一过程即为回调,被当作参数的函数被称为回调函数。在EventManager中:
目标函数:监听的函数,等待消息到来,可理解为监听行为(等待下课铃),该函数执行完后(事件发生收到消息后),去执行之前传入的回调函数;
回调函数:当前listener监听到事件后去执行的函数,可理解为响应的行为(上厕所、打水、给对象发消息),回调函数一般事先已经定好了(想干什么早就打算好了,就等着时机到来);
3. 事件管理者
一个事件管理者的框架如下,主要:
①定义了回调函数,用delegate声明;
②定义了存放信息的字典;
③定义了添加监听关系的函数Add();
④定义了发送事件的的函数SendEvent():
⑤定义了删除关系的相关函数;
using System.Collections.Generic;
using System.Diagnostics.Tracing;
using Unity.VisualScripting;
using UnityEngine;
namespace UnityLearn
{
// 抽象的回调函数,在listener中会定义具体的
public delegate void EventCallBack(EventDataBase data);
public class EventManager : SingleMono<EventManager>
{
// 存放 事件类型-监听者
Dictionary<EventType, List<EventListener>> eventListenerList = new Dictionary<EventType, List<EventListener>>();
// 添加 (事件类型-监听者) 这一关系
public void Add(EventType eventType, object listener, EventCallBack callBack)
{
if (listener == null)
{
return;
}
AddEvent(eventType);
eventListenerList[eventType].Add(new EventListener(listener, callBack));
}
// 添加事件
private void AddEvent(EventType eventType)
{
// 第一次出现这个事件,添加进字典
if (!eventListenerList.ContainsKey(eventType))
{
eventListenerList.Add(eventType, new List<EventListener>());
}
}
// 发送事件
public void SendEvent(EventType eventType, EventDataBase evenData)
{
if (eventListenerList.ContainsKey(eventType))
{
// 获取所有该消息的监听者
List<EventListener> listenerList = eventListenerList[eventType];
for (int i = 0; i < listenerList.Count; ++i)
{
listenerList[i].CallBack(evenData);
}
}
}
// 移除某个监听者
public void RemoveEventListener(EventType eventType, object listener)
{
List<EventListener> listenerList;
if (eventListenerList.TryGetValue(eventType, out listenerList))
{
for (int i = 0; i < listenerList.Count; ++i)
{
listenerList.RemoveAt(i);
return;
}
}
}
// 移除某个监听类别
public void RemoveEvent(EventType eventType)
{
if (eventListenerList.ContainsKey(eventType))
{
eventListenerList.Remove(eventType);
}
}
// 移除所有监听关系
public void Clear()
{
eventListenerList.Clear();
}
}
}
一个事件管理者会管很多很多的事情,即存在很多很多的EventType,上述例子中的“铃声响起”只是众多事情中的一个。每个EventType需要在一个枚举中声明,如:
using Unity.VisualScripting;
namespace UnityLearn
{
public enum EventType
{
MouseInput = 10002,
}
}
4. 监听者
一个监听者的示例代码如下:
using UnityEngine;
namespace UnityLearn
{
public class EventListener
{
public object Listener { get; private set;}
public EventCallBack CallBack { get; private set;}
// 设置:该监听者收到事件发生时去干什么
public EventListener(object listener, EventCallBack callBack)
{
Listener = listener;
CallBack = callBack;
}
}
}
5. 应用例子
最后,有了上述内容,一个应用的例子如下:
using System;
using UnityEngine;
namespace UnityLearn
{
public class A: MonoBehaviour
{
private void Start()
{
// 将本实例,在EventManager中注册消息类型为MouseInput,回调函数为WhatToDo
EventManager.Instance.Add(EventType.MouseInput, this, WhatToDo);
}
void WhatToDo(EventDataBase data)
{
// 回调函数内容
}
}
}
上述例子中,在一个继承MonoBehavior的实例A的Start()函数中定义,在事件管理者EventManager中注册自己,订阅的消息为MouseInput,收到消息后执行的回调函数时WhatToDo。
回调函数的具体内容视实际情况而定。