您现在的位置是:首页 >学无止境 >[Unity] No.3 EventManager事件管理 与 观察者模式网站首页学无止境

[Unity] No.3 EventManager事件管理 与 观察者模式

感天动地大白狗 2023-06-20 12:00:04
简介[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。
回调函数的具体内容视实际情况而定。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。