前言
在开始上代码前, 需要知道这个管理器的大致功能:
- 关卡中唯一存在
- 将事件广播给任何已注册的成员
- 事件是结构体类型
- 在开发过程中应保证该管理器的泛用性
代码部分
EventManager基本雏形
using System;
using System.Collections.Generic;
/// <summary>
/// 事件监听器基本接口
/// </summary>
public interface EventListenerBase { };
/// <summary>
/// 需要为想要侦听的每种类型的事件实现一个公共接口。
/// </summary>
public interface EventListener<T> : EventListenerBase
{
void OnEvent(T eventType);
}
public static class EventManager
{
private static Dictionary<Type, List<EventListenerBase>> _subscribersList;
static EventManager()
{
_subscribersList = new Dictionary<Type, List<EventListenerBase>>();
}
/// <summary>
/// 向事件添加新的订阅者。
/// </summary>
/// <param name="listener">监听器</param>
/// <typeparam name="Event">事件类型</typeparam>
public static void AddListener<Event>(EventListener<Event> listener) where Event : struct
{
}
/// <summary>
/// 从某个事件中删除订阅者。
/// </summary>
/// <param name="listener">监听器</param>
/// <typeparam name="Event">事件类型</typeparam>
public static void RemoveListener<Event>(EventListener<Event> listener) where Event : struct
{
}
/// <summary>
/// 触发事件。订阅它的所有实例都将接收它(并可能对它进行操作)。
/// </summary>
/// <param name="newEvent">触发的事件</param>
/// <typeparam name="Event">第一个类型参数</typeparam>
public static void TriggerEvent<Event>(Event newEvent) where Event : struct
{
}
}
对EventManager稍加修饰
using System;
using System.Collections.Generic;
/// <summary>
/// 事件监听器基本接口
/// </summary>
public interface EventListenerBase { };
/// <summary>
/// 需要为想要侦听的每种类型的事件实现一个公共接口。
/// </summary>
public interface EventListener<T> : EventListenerBase
{
void OnEvent(T eventType);
}
public static class EventManager
{
private static Dictionary<Type, List<EventListenerBase>> _subscribersList;
static EventManager()
{
_subscribersList = new Dictionary<Type, List<EventListenerBase>>();
}
/// <summary>
/// 向事件添加新的订阅者。
/// </summary>
/// <param name="listener">监听器</param>
/// <typeparam name="Event">事件类型</typeparam>
public static void AddListener<Event>(EventListener<Event> listener) where Event : struct
{
Type eventType = typeof(Event);
if (!_subscribersList.ContainsKey(eventType))
{
_subscribersList[eventType] = new List<EventListenerBase>();
}
if (!SubscriptionExists(eventType, listener))
{
_subscribersList[eventType].Add(listener);
}
}
/// <summary>
/// 从某个事件中删除订阅者。
/// </summary>
/// <param name="listener">监听器</param>
/// <typeparam name="Event">事件类型</typeparam>
public static void RemoveListener<Event>(EventListener<Event> listener) where Event : struct
{
Type eventType = typeof(Event);
if (!_subscribersList.ContainsKey(eventType))
{
#if EVENTROUTER_THROWEXCEPTIONS
throw new ArgumentException( string.Format( "删除侦听器 \"{0}\", 但是事件类型 \"{1}\" 不是注册.", listener, eventType.ToString() ) );
#else
return;
#endif
}
List<EventListenerBase> subscriberList = _subscribersList[eventType];
#if EVENTROUTER_THROWEXCEPTIONS
bool listenerFound = false;
#endif
for (int i = subscriberList.Count - 1; i >= 0; i--)
{
if (subscriberList[i] == listener)
{
subscriberList.Remove(subscriberList[i]);
#if EVENTROUTER_THROWEXCEPTIONS
listenerFound = true;
#endif
if (subscriberList.Count == 0)
{
_subscribersList.Remove(eventType);
}
return;
}
}
#if EVENTROUTER_THROWEXCEPTIONS
if( !listenerFound )
{
throw new ArgumentException( string.Format( "删除侦听器, 但是接收者没有订阅事件类型 \"{0}\".", eventType.ToString() ) );
}
#endif
}
/// <summary>
/// 触发事件。订阅它的所有实例都将接收它(并可能对它进行操作)。
/// </summary>
/// <param name="newEvent">触发的事件</param>
/// <typeparam name="Event">第一个类型参数</typeparam>
public static void TriggerEvent<Event>(Event newEvent) where Event : struct
{
List<EventListenerBase> list;
if (!_subscribersList.TryGetValue(typeof(Event), out list))
#if EVENTROUTER_REQUIRELISTENER
throw new ArgumentException( string.Format( "正在尝试发送类型为 \"{0}\", 但是没有找到这种类型的监听器. 确保 this.Subscribe<{0}>(EventRouter) 已被调用, 或者此事件的所有侦听器尚未取消订阅。", typeof( Event ).ToString() ) );
#else
return;
#endif
for (int i = list.Count - 1; i >= 0; i--)
{
(list[i] as EventListener<Event>).OnEvent(newEvent);
}
}
/// <summary>
/// 检查是否有特定类型事件的订阅者
/// </summary>
/// <returns><c>true</c>, 已被订阅, <c>false</c> 未被订阅</returns>
/// <param name="type">类型</param>
/// <param name="receiver">接收器</param>
private static bool SubscriptionExists(Type type, EventListenerBase receiver)
{
List<EventListenerBase> receivers;
if (!_subscribersList.TryGetValue(type, out receivers)) return false;
bool exists = false;
for (int i = receivers.Count - 1; i >= 0; i--)
{
if (receivers[i] == receiver)
{
exists = true;
break;
}
}
return exists;
}
}
最后添加一个注册的拓展方法
(这个类放到EventManager.cs中的最后即可)
/// <summary>
/// 事件注册。静态类,允许任何类启动或停止侦听事件。将注册与移除优化为扩展方法
/// </summary>
public static class EventRegister
{
public static void EventStartListening<EventType>(this EventListener<EventType> caller) where EventType : struct
{
EventManager.AddListener<EventType>(caller);
}
public static void EventStopListening<EventType>(this EventListener<EventType> caller) where EventType : struct
{
EventManager.RemoveListener<EventType>(caller);
}
}
大功告成!
使用方法与测试
创建一个名为 “EventTest” 的测试脚本, 并将其挂载到一个空物体上
首先在类中这样(创建结构体)
public enum EventTypes
{
Type1,
Type2
}
public struct TestEvent
{
/// <summary>
/// 该事件中事件类型
/// </summary>
public EventTypes EventType;
/// <summary>
/// 该事件中的一个key
/// </summary>
public string Key;
public TestEvent(EventTypes eventType, string key = null)
{
EventType = eventType;
this.Key = key;
}
static TestEvent e;
public static void Trigger(EventTypes eventType, string key = null)
{
e.EventType = eventType;
e.Key = key;
EventManager.TriggerEvent(e);
}
}
然后在类中这样(注册与使用)
public class EventTest : MonoBehaviour, EventListener<TestEvent>
{
void Start()
{
// 监听
this.EventStartListening<TestEvent>();
// 触发测试事件中的 Type1 类型中关键字 "TA"
TestEvent.Trigger(EventTypes.Type1, "TA");
}
private void OnDisable()
{
// 停止监听
this.EventStopListening<TestEvent>();
}
void Update()
{
}
public void OnEvent(TestEvent eventType)
{
switch (eventType.EventType)
{
case EventTypes.Type1:
Debug.Log($"{eventType.Key}");
break;
}
}
}
当然在刚刚继承接口时是这样的
只要实现接口就可以了。点击运行即可获得以下结果
完整测试代码
using UnityEngine;
public enum EventTypes
{
Type1,
Type2
}
public struct TestEvent
{
/// <summary>
/// 该事件中事件类型
/// </summary>
public EventTypes EventType;
/// <summary>
/// 该事件中的一个key
/// </summary>
public string Key;
public TestEvent(EventTypes eventType, string key = null)
{
EventType = eventType;
this.Key = key;
}
static TestEvent e;
public static void Trigger(EventTypes eventType, string key = null)
{
e.EventType = eventType;
e.Key = key;
EventManager.TriggerEvent(e);
}
}
public class EventTest : MonoBehaviour, EventListener<TestEvent>
{
void Start()
{
// 监听
this.EventStartListening<TestEvent>();
// 触发测试事件中的 Type1 类型中关键字 "TA"
TestEvent.Trigger(EventTypes.Type1, "TA");
}
private void OnDisable()
{
// 停止监听
this.EventStopListening<TestEvent>();
}
public void OnEvent(TestEvent eventType)
{
switch (eventType.EventType)
{
case EventTypes.Type1:
Debug.Log($"{eventType.Key}");
break;
}
}
}
结尾
个人认为这个事件管理器泛用性还是可以的, 反正我用的这几年中还是挺好用的。