目的
解决代码之间耦合性问题
解决方法
利用委托封装事件方法,然后利用广播和监听事件来实现解耦。
优点:解决代码和代码之间的耦合性,每个脚本只需要关心自己要干的事情,不需要和外界进行联系。
缺点:添加监听时泛型的类型问题,必须明确参数的顺序,不可以出错,如果出错回报错。
- 委托脚本
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);
- 事件处理中心类
EventCenter.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EventCenter
{
private static Dictionary<EventType, Delegate> m_EventTable = new Dictionary<EventType, Delegate>();
#region 脚本精简,将重复性脚本提取出来
/// <summary>
/// 添加监听
/// </summary>
private static void OnListenerAdding(EventType eventType, Delegate callBack)
{
//判断事件码是否存在,如果不存在就添加
if (!m_EventTable.ContainsKey(eventType))
{
m_EventTable.Add(eventType, null);
}
//拿到m_EventTable所对应的委托
Delegate d = m_EventTable[eventType];
//判断要添加的委托与当前事件码对应的委托类型是否一致,一致才可以绑定
if (d != null && d.GetType() != callBack.GetType())
{
throw new Exception(string.Format("尝试为事件码{0}添加不同类型的委托," +
"当前事件所对应的委托是{1},要添加的委托类型是{2}", eventType, d.GetType(), callBack.GetType()));
}
}
/// <summary>
/// 移除监听前
/// </summary>
private static void OnListenerRemoving(EventType eventType, Delegate callBack)
{
//判断事件码是否存在
if (m_EventTable.ContainsKey(eventType))
{
Delegate d = m_EventTable[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));
}
}
/// <summary>
/// 移除监听后
/// </summary>
private static void OnListenerRemoved(EventType eventType)
{
//判断当前事件码对应的委托是否为空,为空的话事件码无用,移除事件码
if (m_EventTable[eventType] == null)
{
m_EventTable.Remove(eventType);
}
}
#endregion
/// <summary>
/// 无参的添加监听
/// </summary>
public static void AddListener(EventType eventType, CallBack callBack)
{
OnListenerAdding(eventType, callBack);
m_EventTable[eventType] = (CallBack)m_EventTable[eventType] + callBack;
}
/// <summary>
/// 单个参数的监听
/// </summary>
public static void AddListener<T>(EventType eventType, CallBack<T> callBack)
{
OnListenerAdding(eventType, callBack);
m_EventTable[eventType] = (CallBack<T>)m_EventTable[eventType] + callBack;
}
/// <summary>
/// 两个参数的监听
/// </summary>
public static void AddListener<T, X>(EventType eventType, CallBack<T, X> callBack)
{
OnListenerAdding(eventType, callBack);
m_EventTable[eventType] = (CallBack<T, X>)m_EventTable[eventType] + callBack;
}
/// <summary>
/// 三个参数的监听
/// </summary>
public static void AddListener<T, X, Y>(EventType eventType, CallBack<T, X, Y> callBack)
{
OnListenerAdding(eventType, callBack);
m_EventTable[eventType] = (CallBack<T, X, Y>)m_EventTable[eventType] + callBack;
}
/// <summary>
/// 四个参数的监听
/// </summary>
public static void AddListener<T, X, Y, Z>(EventType eventType, CallBack<T, X, Y, Z> callBack)
{
OnListenerAdding(eventType, callBack);
m_EventTable[eventType] = (CallBack<T, X, Y, Z>)m_EventTable[eventType] + callBack;
}
/// <summary>
/// 五个参数的监听
/// </summary>
public static void AddListener<T, X, Y, Z, W>(EventType eventType, CallBack<T, X, Y, Z, W> callBack)
{
OnListenerAdding(eventType, callBack);
m_EventTable[eventType] = (CallBack<T, X, Y, Z, W>)m_EventTable[eventType] + callBack;
}
/// <summary>
/// 无参的移除监听
/// </summary>
public static void RemoveListener(EventType eventType, CallBack callBack)
{
OnListenerRemoving(eventType, callBack);
m_EventTable[eventType] = (CallBack)m_EventTable[eventType] - callBack;
OnListenerRemoved(eventType);
}
/// <summary>
/// 一个参数的移除监听
/// </summary>
public static void RemoveListener<T>(EventType eventType, CallBack<T> callBack)
{
OnListenerRemoving(eventType, callBack);
m_EventTable[eventType] = (CallBack<T>)m_EventTable[eventType] - callBack;
OnListenerRemoved(eventType);
}
/// <summary>
/// 两个参数的移除监听
/// </summary>
public static void RemoveListener<T, X>(EventType eventType, CallBack<T, X> callBack)
{
OnListenerRemoving(eventType, callBack);
m_EventTable[eventType] = (CallBack<T, X>)m_EventTable[eventType] - callBack;
OnListenerRemoved(eventType);
}
/// <summary>
/// 三个参数的移除监听
/// </summary>
public static void RemoveListener<T, X, Y>(EventType eventType, CallBack<T, X, Y> callBack)
{
OnListenerRemoving(eventType, callBack);
m_EventTable[eventType] = (CallBack<T, X, Y>)m_EventTable[eventType] - callBack;
OnListenerRemoved(eventType);
}
/// <summary>
/// 四个参数的移除监听
/// </summary>
public static void RemoveListener<T, X, Y, Z>(EventType eventType, CallBack<T, X, Y, Z> callBack)
{
OnListenerRemoving(eventType, callBack);
m_EventTable[eventType] = (CallBack<T, X, Y, Z>)m_EventTable[eventType] - callBack;
OnListenerRemoved(eventType);
}
/// <summary>
/// 无个参数的移除监听
/// </summary>
public static void RemoveListener<T, X, Y, Z, W>(EventType eventType, CallBack<T, X, Y, Z, W> callBack)
{
OnListenerRemoving(eventType, callBack);
m_EventTable[eventType] = (CallBack<T, X, Y, Z, W>)m_EventTable[eventType] - callBack;
OnListenerRemoved(eventType);
}
/// <summary>
/// 无参广播
/// </summary>
public static void Broadcast(EventType eventType)
{
Delegate d;
if (m_EventTable.TryGetValue(eventType, out d))
{
CallBack callBack = d as CallBack;
if (callBack != null)
{
callBack();
}
else
{
throw new Exception(string.Format("广播事件错误错误:事件{0}对应的委托具有不同的类型", eventType));
}
}
}
/// <summary>
/// 一个参数的广播
/// </summary>
public static void Broadcast<T>(EventType eventType, T arg)
{
Delegate d;
if (m_EventTable.TryGetValue(eventType, out d))
{
CallBack<T> callBack = d as CallBack<T>;
if (callBack != null)
{
callBack(arg);
}
else
{
throw new Exception(string.Format("广播事件错误错误:事件{0}对应的委托具有不同的类型", eventType));
}
}
}
// <summary>
/// 两个参数的广播
/// </summary>
public static void Broadcast<T, X>(EventType eventType, T arg1, X arg2)
{
Delegate d;
if (m_EventTable.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));
}
}
}
// <summary>
/// 三个参数的广播
/// </summary>
public static void Broadcast<T, X, Y>(EventType eventType, T arg1, X arg2, Y arg3)
{
Delegate d;
if (m_EventTable.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));
}
}
}
// <summary>
/// 四个参数的广播
/// </summary>
public static void Broadcast<T, X, Y, Z>(EventType eventType, T arg1, X arg2, Y arg3, Z arg4)
{
Delegate d;
if (m_EventTable.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));
}
}
}
// <summary>
/// 五个参数的广播
/// </summary>
public static void Broadcast<T, X, Y, Z, W>(EventType eventType, T arg1, X arg2, Y arg3, Z arg4, W arg5)
{
Delegate d;
if (m_EventTable.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));
}
}
}
}
- 事件码枚举类
分别对应无参数、1参数、2参数、3参数、4参数、5参数
EventType.cs
public enum EventType
{
ShowText0,
ShowText1,
ShowText2,
ShowText3,
ShowText4,
ShowText5,
}
测试
共有两个类用于测试
ShowText .cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ShowText : MonoBehaviour
{
private void Awake()
{
gameObject.SetActive(false);
EventCenter.AddListener(EventType.ShowText0, Show0);
EventCenter.AddListener<string>(EventType.ShowText1, Show1);
EventCenter.AddListener<string, float>(EventType.ShowText2, Show2);
EventCenter.AddListener<string, float, int>(EventType.ShowText3, Show3);
EventCenter.AddListener<string, float, int, string>(EventType.ShowText4, Show4);
EventCenter.AddListener<string, float, int, string, int>(EventType.ShowText5, Show5);
}
private void OnDestroy()
{
EventCenter.RemoveListener(EventType.ShowText0, Show0);
EventCenter.RemoveListener<string>(EventType.ShowText1, Show1);
EventCenter.RemoveListener<string, float>(EventType.ShowText2, Show2);
EventCenter.RemoveListener<string, float, int>(EventType.ShowText3, Show3);
EventCenter.RemoveListener<string, float, int, string>(EventType.ShowText4, Show4);
EventCenter.RemoveListener<string, float, int, string, int>(EventType.ShowText5, Show5);
}
public void Show0()
{
gameObject.SetActive(true);
}
public void Show1(string str)
{
gameObject.SetActive(true);
GetComponent<Text>().text = str;
}
public void Show2(string str, float a)
{
gameObject.SetActive(true);
GetComponent<Text>().text = str + a;
}
public void Show3(string str, float a, int b)
{
gameObject.SetActive(true);
GetComponent<Text>().text = str + a + b;
}
public void Show4(string str, float a, int b, string str2)
{
gameObject.SetActive(true);
GetComponent<Text>().text = str + a + b + str2;
}
public void Show5(string str, float a, int b, string str2, int c)
{
gameObject.SetActive(true);
GetComponent<Text>().text = str + a + b + str2 + c;
}
}
BtnClick.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class BtnClick : MonoBehaviour
{
private Button noParameter;
private Button oneParameter;
private Button twoParameter;
private Button threeParameter;
private Button fourParameter;
private Button fiveParameter;
private void Awake()
{
noParameter = transform.Find("NoParameter").GetComponent<Button>();
oneParameter = transform.Find("OneParameter ").GetComponent<Button>();
twoParameter = transform.Find("TwoParameter").GetComponent<Button>();
threeParameter = transform.Find("ThreeParameter").GetComponent<Button>();
fourParameter = transform.Find("FourParameter").GetComponent<Button>();
fiveParameter = transform.Find("FiveParameter").GetComponent<Button>();
}
private void Start()
{
noParameter.onClick.AddListener(()=>
{
EventCenter.Broadcast(EventType.ShowText0);
});
oneParameter.onClick.AddListener(() =>
{
EventCenter.Broadcast(EventType.ShowText1, "你好1");
});
twoParameter.onClick.AddListener(() =>
{
EventCenter.Broadcast(EventType.ShowText2, "你好1", 2.0f);
});
threeParameter.onClick.AddListener(() =>
{
EventCenter.Broadcast(EventType.ShowText3, "你好1", 2.0f, 3);
});
fourParameter.onClick.AddListener(() =>
{
EventCenter.Broadcast(EventType.ShowText4, "你好1", 2.0f, 3, "吗?4");
});
fiveParameter.onClick.AddListener(() =>
{
EventCenter.Broadcast(EventType.ShowText5, "你好1", 2.0f, 3, "吗?4", 5);
});
}
}
脚本挂载与界面如下图所示,其中ShowText .cs挂在Text上,BtnClick .cs挂在Buttons上

这篇博客介绍了如何在Unity中通过创建委托和事件中心类来实现代码的解耦合。事件中心类(EventCenter)管理事件监听的添加、移除及广播,使用不同参数数量的回调方法,确保了各组件间的独立性。通过添加和移除监听,以及无参数到五参数的广播功能,实现了灵活的消息传递。在测试部分,展示了如何在不同场景下订阅和触发事件,以展示系统的有效性。

542

被折叠的 条评论
为什么被折叠?



