一个高级的EventManager(自认为)

前言

在开始上代码前, 需要知道这个管理器的大致功能:

  1. 关卡中唯一存在
  2. 将事件广播给任何已注册的成员
  3. 事件是结构体类型
  4. 在开发过程中应保证该管理器的泛用性

代码部分

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;
        }
    }
}

结尾

个人认为这个事件管理器泛用性还是可以的, 反正我用的这几年中还是挺好用的。

  • 8
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值