Unity3d的事件分发系统的实现
肺炎期间在家自行隔离,在家无聊,学习一下,看到了siki学院的Carson老师的《Unity高度解耦和 - 事件的监听与广播系统》课程,这里感谢Carson老师。对比自己学习工作的项目中事件分发系统。总结出一些体会。
事件分发系统是一个大的项目必不可少的模块,一个较大的项目,各个模块如果耦合度太高,维护起来成本就比较高,故障率就会不断的增大,记得大学课本上说到的软件工程中的一个概念-判断软件设计好坏的标准“高内聚,低耦合”。事件分发系统就是用来解耦的。
首先需要了解一下委托的概念,c#基础这里就不做陈述。其次了解什么观察者模式,这里用到了设计模式中常见的观察者模式。当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。
观察者模式的优缺点:优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。缺点: 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
废话不多说,先上代码
这是Carson老师的代码
1.EventCenter.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EventCenter
{
private static Dictionary<EventType, Delegate> eventDic = new Dictionary<EventType, Delegate>();
private static void OnListenerAdding(EventType eventType, Delegate callBack)
{
if (!eventDic.ContainsKey(eventType))
{
eventDic.Add(eventType, null);
}
Delegate d = eventDic[eventType];
if (d != null && d.GetType() != callBack.GetType())
{
throw new Exception(string.Format("尝试为事件{0}添加不同类型的委托,当前事件所对应的委托是{1},要添加的委托类型为{2}", eventType, d.GetType(), callBack.GetType()));
}
}
private static void OnListenerRemoving(EventType eventType, Delegate callBack)
{
if (eventDic.ContainsKey(eventType))
{
Delegate d = eventDic[eventType];
if (d == null)
{
throw new Exception(string.Format("移除监听错误:事件{0}没有对应的委托", eventType));
}
else if (d.GetType() != callBack.GetType())
{
throw new Exception(string.Format("移除监听错误:尝试为事件{0}移除不同类型的委托,当前委托类型为{1},要移除的委托类型为{2}", eventType, d.GetType(), callBack.GetType()));
}
}
else
{
throw new Exception(string.Format("移除监听错误:没有事件码{0}", eventType));
}
}
private static void OnListenerRemoved(EventType eventType)
{
if (eventDic[eventType] == null)
{
eventDic.Remove(eventType);
}
}
//no parameters
public static void AddListener(EventType eventType, CallBack callBack)
{
OnListenerAdding(eventType, callBack);
eventDic[eventType] = (CallBack)eventDic[eventType] + callBack;
}
//Single parameters
public static void AddListener<T>(EventType eventType, CallBack<T> callBack)
{
OnListenerAdding(eventType, callBack);
eventDic[eventType] = (CallBack<T>)eventDic[eventType] + callBack;
}
//two parameters
public static void AddListener<T, X>(EventType eventType, CallBack<T, X> callBack)
{
OnListenerAdding(eventType, callBack);
eventDic[eventType] = (CallBack<T, X>)eventDic[eventType] + callBack;
}
//three parameters
public static void AddListener<T, X, Y>(EventType eventType, CallBack<T, X, Y> callBack)
{
OnListenerAdding(eventType, callBack);
eventDic[eventType] = (CallBack<T, X, Y>)eventDic[eventType] + callBack;
}
//four parameters
public static void AddListener<T, X, Y, Z>(EventType eventType, CallBack<T, X, Y, Z> callBack)
{
OnListenerAdding(eventType, callBack);
eventDic[eventType] = (CallBack<T, X, Y, Z>)eventDic[eventType] + callBack;
}
//five parameters
public static void AddListener<T, X, Y, Z, W>(EventType eventType, CallBack<T, X, Y, Z, W> callBack)
{
OnListenerAdding(eventType, callBack);
eventDic[eventType] = (CallBack<T, X, Y, Z, W>)eventDic[eventType] + callBack;
}
//no parameters
public static void RemoveListener(EventType eventType, CallBack callBack)
{
OnListenerRemoving(eventType, callBack);
eventDic[eventType] = (CallBack)eventDic[eventType] - callBack;
OnListenerRemoved(eventType);
}
//single parameters
public static void RemoveListener<T>(EventType eventType, CallBack<T> callBack)
{
OnListenerRemoving(eventType, callBack);
eventDic[eventType] = (CallBack<T>)eventDic[eventType] - callBack;
OnListenerRemoved(eventType);
}
//two parameters
public static void RemoveListener<T, X>(EventType eventType, CallBack<T, X> callBack)
{
OnListenerRemoving(eventType, callBack);
eventDic[eventType] = (CallBack<T, X>)eventDic[eventType] - callBack;
OnListenerRemoved(eventType);
}
//three parameters
public static void RemoveListener<T, X, Y>(EventType eventType, CallBack<T, X, Y> callBack)
{
OnListenerRemoving(eventType, callBack);
eventDic[eventType] = (CallBack<T, X, Y>)eventDic[eventType] - callBack;
OnListenerRemoved(eventType);
}
//four parameters
public static void RemoveListener<T, X, Y, Z>(EventType eventType, CallBack<T, X, Y, Z> callBack)
{
OnListenerRemoving(eventType, callBack);
eventDic[eventType] = (CallBack<T, X, Y, Z>)eventDic[eventType] - callBack;
OnListenerRemoved(eventType);
}
//five parameters
public static void RemoveListener<T, X, Y, Z, W>(EventType eventType, CallBack<T, X, Y, Z, W> callBack)
{
OnListenerRemoving(eventType, callBack);
eventDic[eventType] = (CallBack<T, X, Y, Z, W>)eventDic[eventType] - callBack;
OnListenerRemoved(eventType);
}
//no parameters
public static void Broadcast(EventType eventType)
{
Delegate d;
if (eventDic.TryGetValue(eventType, out d))
{
CallBack callBack = d as CallBack;
if (callBack != null)
{
callBack();
}
else
{
throw new Exception(string.Format("广播事件错误:事件{0}对应委托具有不同的类型", eventType));
}
}
}
//single parameters
public static void Broadcast<T>(EventType eventType, T arg)
{
Delegate d;
if (eventDic.TryGetValue(eventType, out d))
{
CallBack<T> callBack = d as CallBack<T>;
if (callBack != null)
{
callBack(arg);
}
else
{
throw new Exception(string.Format("广播事件错误:事件{0}对应委托具有不同的类型", eventType));
}
}
}
//two parameters
public static void Broadcast<T, X>(EventType eventType, T arg1, X arg2)
{
Delegate d;
if (eventDic.TryGetValue(eventType, out d))
{
CallBack<T, X> callBack = d as CallBack<T, X>;
if (callBack != null)
{
callBack(arg1, arg2);
}
else
{
throw new Exception(string.Format("广播事件错误:事件{0}对应委托具有不同的类型", eventType));
}
}
}
//three parameters
public static void Broadcast<T, X, Y>(EventType eventType, T arg1, X arg2, Y arg3)
{
Delegate d;
if (eventDic.TryGetValue(eventType, out d))
{
CallBack<T, X, Y> callBack = d as CallBack<T, X, Y>;
if (callBack != null)
{
callBack(arg1, arg2, arg3);
}
else
{
throw new Exception(string.Format("广播事件错误:事件{0}对应委托具有不同的类型", eventType));
}
}
}
//four parameters
public static void Broadcast<T, X, Y, Z>(EventType eventType, T arg1, X arg2, Y arg3, Z arg4)
{
Delegate d;
if (eventDic.TryGetValue(eventType, out d))
{
CallBack<T, X, Y, Z> callBack = d as CallBack<T, X, Y, Z>;
if (callBack != null)
{
callBack(arg1, arg2, arg3, arg4);
}
else
{
throw new Exception(string.Format("广播事件错误:事件{0}对应委托具有不同的类型", eventType));
}
}
}
//five parameters
public static void Broadcast<T, X, Y, Z, W>(EventType eventType, T arg1, X arg2, Y arg3, Z arg4, W arg5)
{
Delegate d;
if (eventDic.TryGetValue(eventType, out d))
{
CallBack<T, X, Y, Z, W> callBack = d as CallBack<T, X, Y, Z, W>;
if (callBack != null)
{
callBack(arg1, arg2, arg3, arg4, arg5);
}
else
{
throw new Exception(string.Format("广播事件错误:事件{0}对应委托具有不同的类型", eventType));
}
}
}
}
2.CallBack.cs
public delegate void CallBack();
public delegate void CallBack<T>(T arg);
public delegate void CallBack<T, X>(T arg1, X arg2);
public delegate void CallBack<T, X, Y>(T arg1, X arg2, Y arg3);
public delegate void CallBack<T, X, Y, Z>(T arg1, X arg2, Y arg3, Z arg4);
public delegate void CallBack<T, X, Y, Z, W>(T arg1, X arg2, Y arg3, Z arg4, W arg5);
下面的是曾经用过的一个事件分发系统
/**
*Copyright(C) 2015 by #FrameworkStudyDemo#
*All rights reserved.
*FileName: #EventDispatcher.cs#
*Author: #zhangliang#
*Version: #1.0#
*UnityVersion:#2018.4.2f#
*Date: #2020/2/14#
*Description: 事件派发器:用于添加事件监听,移除事件监听,事件是否存在监听,事件派发(执行监听的事件)
*History:
*/
using System.Collections.Generic;
using UnityEngine;
#region 事件参数
/// <summary>
/// 事件参数
/// </summary>
public interface IEventParam
{
}
public class StringEventParam : IEventParam
{
public string value;
public StringEventParam(string str)
{
this.value = str;
}
}
public class IntEventParam : IEventParam
{
public int value;
public IntEventParam(int param)
{
this.value = param;
}
}
public class ObjectEventParam : IEventParam
{
public object value;
public ObjectEventParam(object param)
{
this.value = param;
}
}
#endregion
/// <summary>
/// 事件派发器对外接口
/// </summary>
public interface IEventDispatcher
{
/// <summary>
/// 添加事件监听
/// </summary>
void AddEventListener(EventType eventType, EventDelegate eventDelegate);
/// <summary>
/// 移除事件监听
/// </summary>
void RemoveEventListener(EventType eventType, EventDelegate eventDelegate);
/// <summary>
/// 是否存在事件监听
/// </summary>
/// <param name="eventType"></param>
/// <param name="eventDelegate"></param>
/// <returns></returns>
bool HasEventListener(EventType eventType, EventDelegate eventDelegate);
/// <summary>
/// 派发事件
/// </summary>
void DispatcherEvent(EventType eventType, IEventParam eventParam);
/// <summary>
/// 清除所有监听
/// </summary>
void RemoveAllListener();
}
/// <summary>
/// 委托定义
/// </summary>
/// <param name="IE"></param>
public delegate void EventDelegate(IEventParam IE);
public class EventDispatcher : IEventDispatcher
{
private static EventDispatcher instance;
/// <summary>
/// 单例
/// </summary>
public static EventDispatcher Instance
{
get
{
if (instance == null)
{
instance = new EventDispatcher();
}
return instance;
}
}
/// <summary>
/// 已经注册的事件字典
/// </summary>
private Dictionary<EventType, List<EventDelegate>> eventDic = new Dictionary<EventType, List<EventDelegate>>();
/// <summary>
/// 添加事件监听
/// </summary>
/// <param name="eventType"></param>
/// <param name="eventDelegate"></param>
public void AddEventListener(EventType eventType, EventDelegate eventDelegate)
{
if (eventDic == null)
{
eventDic = new Dictionary<EventType, List<EventDelegate>>();
}
if (!eventDic.ContainsKey(eventType))
{
List<EventDelegate> delegateList = new List<EventDelegate>();
delegateList.Add(eventDelegate);
eventDic.Add(eventType, delegateList);
}
else
{
List<EventDelegate> delegateList = eventDic[eventType];
if (!delegateList.Contains(eventDelegate))
{
delegateList.Add(eventDelegate);
eventDic[eventType] = delegateList;
}
}
}
/// <summary>
/// 移除事件监听
/// </summary>
/// <param name="eventType"></param>
/// <param name="eventDelegate"></param>
public void RemoveEventListener(EventType eventType, EventDelegate eventDelegate)
{
if (eventDic.ContainsKey(eventType))
{
if (eventDic[eventType].Contains(eventDelegate))
{
eventDic[eventType].Remove(eventDelegate);
if (eventDic[eventType].Count == 0)
{
eventDic.Remove(eventType);
}
}
else
{
Debug.Log(" EventType:" + eventType + " EventDelegate:" + eventDelegate.Method + " not exit");
}
}
else
{
Debug.Log(" EventType:" + eventType + " not exit");
}
}
/// <summary>
/// 是否存在事件监听
/// </summary>
/// <param name="eventType"></param>
/// <param name="eventDelegate"></param>
/// <returns></returns>
public bool HasEventListener(EventType eventType, EventDelegate eventDelegate)
{
if (eventDic.ContainsKey(eventType))
{
if (eventDic[eventType].Contains(eventDelegate))
{
return true;
}
}
return false;
}
/// <summary>
/// 派发事件
/// </summary>
/// <param name="eventType"></param>
/// <param name="eventDelegate"></param>
public void DispatcherEvent(EventType eventType, IEventParam eventParam)
{
if (eventDic.ContainsKey(eventType))
{
List<EventDelegate> delegateList = eventDic[eventType];
for (int i = 0; i < delegateList.Count; i++)
{
delegateList[i](eventParam);
}
}
}
/// <summary>
/// 清除所有监听
/// </summary>
public void RemoveAllListener()
{
if (eventDic.Count != 0)
{
eventDic.Clear();
}
}
}
这两个事件派发器大致类似,只是第二种对于同一个事件可以有多个响应,例如,一个项目中,一个大的模块中有多个小的模块,由不同的开发进行开发,当某个事件发生时,需要出发多有小模块里的刷新,这是我们只需要监听一个事件就行了。其次是针对参数类型进行封装,这样不需要使用很多的参数,当然这个是否是优点或者缺点也因人而异了