Unity 事件监听与广播(高度解耦合,观察者模式)

1. 目的

使用观察者模式降低模块间的耦合性

2. 主要思路

  1. 通过C# 的 Dictionary 存放事件码和事件的委托
  2. 添加事件:
    • 判断字典是否有该事件码,没有添加
    • 判断当前委托类型与添加的事件码的类型是否一致
    • 最后订阅该事件
  3. 移除事件:
    • 先判断事件码是否存在
    • 取消订阅
    • 最后判断事件码是否为空,是null则移除事件码
  4. 广播事件:
    • 若事件委托不为null,广播事件

3. 基础类

  • SingletonBase 单例模式基类
/*
 * FileName:    SingletonBase
 * Author:      ming
 * CreateTime:  2023/6/28 11:46:00
 * Description: 单例模式基类
 * 
*/
using UnityEngine;
using System.Collections;

public class SingletonBase<T> where T : new() {
    
    
    private static T _Instance;

    public static T GetInstance()
    {
    
    
        if (_Instance == null) _Instance = new T();
        return _Instance;
    }
}
  • EventEnum 事件枚举类
public enum EventEnum
{
    
    
    
}
  • CallBack 委托类
/*
 * FileName:    CallBack
 * Author:      ming
 * CreateTime:  2023/6/28 14:22:38
 * Description: 委托
 * 
*/

// 无参委托
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);

4. EventCenter 事件中心类

/*
 * FileName:    EventCenter
 * Author:      ming
 * CreateTime:  2023/6/28 14:15:39
 * Description: 事件中心类,添加、删除、分发事件
 * 
*/
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;

public class EventCenter : MonoBehaviour
{
    
    
    // 字典,用于存放事件码和委托对应
    private static Dictionary<EventEnum, Delegate> m_EventTable = new Dictionary<EventEnum, Delegate>();

    #region 添加和移除事件前的判断

    // 添加事件监听前的判断
    private static void OnAddListenerJudge(EventEnum eventEnum, Delegate callBack) {
    
    
        // 先判断事件码是否存在于字典中,不存在则先添加
        if (!m_EventTable.ContainsKey(eventEnum)) {
    
    
            // 先给字典添加事件码,委托设置为空
            m_EventTable.Add(eventEnum, null);
        }

        // 判断当前事件码的委托类型和要添加的委托类型是否一致,不一致不能添加,抛出异常
        Delegate d = m_EventTable[eventEnum];
        if (d != null && d.GetType() != callBack.GetType()) {
    
    
            throw new Exception(string.Format("尝试为事件码{0}添加不同事件的委托,当前事件所对应的委托是{1},要添加的委托类型{2}", eventEnum, d.GetType(), callBack.GetType()));
        }
    }

    // 移除事件码前的判断
    private static void OnRemoveListenerBeforeJudge(EventEnum eventEnum) {
    
    
        // 判断是否包含指定事件码
        if (!m_EventTable.ContainsKey(eventEnum)) {
    
    
            throw new Exception(string.Format("移除监听错误;没有事件码", eventEnum));
        }
    }

    // 移除事件码后的判断,用于移除字典中空的事件码
    private static void OnRemoveListenerLaterJudge(EventEnum eventEnum) {
    
    
        if (m_EventTable[eventEnum] == null) {
    
    
            m_EventTable.Remove(eventEnum);
        }
    }

    #endregion

    #region 添加监听
    // 无参
    public static void AddListener(EventEnum eventEnum, CallBack callBack) {
    
    
        OnAddListenerJudge(eventEnum, callBack);
        m_EventTable[eventEnum] = (CallBack)m_EventTable[eventEnum] + callBack;
    }
    // 带参数
    public static void AddListener<T>(EventEnum eventEnum, CallBack<T> callBack) {
    
    
        OnAddListenerJudge(eventEnum, callBack);
        m_EventTable[eventEnum] = (CallBack<T>)m_EventTable[eventEnum] + callBack;
    }
    public static void AddListener<T, X>(EventEnum eventEnum, CallBack<T, X> callBack) {
    
    
        OnAddListenerJudge(eventEnum, callBack);
        m_EventTable[eventEnum] = (CallBack<T, X>)m_EventTable[eventEnum] + callBack;
    }
    public static void AddListener<T, X, Y>(EventEnum eventEnum, CallBack<T, X, Y> callBack) {
    
    
        OnAddListenerJudge(eventEnum, callBack);
        m_EventTable[eventEnum] = (CallBack<T, X, Y>)m_EventTable[eventEnum] + callBack;
    }
    public static void AddListener<T, X, Y, Z>(EventEnum eventEnum, CallBack<T, X, Y, Z> callBack) {
    
    
        OnAddListenerJudge(eventEnum, callBack);
        m_EventTable[eventEnum] = (CallBack<T, X, Y, Z>)m_EventTable[eventEnum] + callBack;
    }
    public static void AddListener<T, X, Y, Z, W>(EventEnum eventEnum, CallBack<T, X, Y, Z, W> callBack) {
    
    
        OnAddListenerJudge(eventEnum, callBack);
        m_EventTable[eventEnum] = (CallBack<T, X, Y, Z, W>)m_EventTable[eventEnum] + callBack;
    }

    #endregion

    #region 移除监听

    public static void RemoveListener(EventEnum eventEnum, CallBack callBack) {
    
    
        OnRemoveListenerBeforeJudge(eventEnum);
        m_EventTable[eventEnum] = (CallBack)m_EventTable[eventEnum] - callBack;
        OnRemoveListenerLaterJudge(eventEnum);
    }

    public static void RemoveListener<T>(EventEnum eventEnum, CallBack<T> callBack) {
    
    
        OnRemoveListenerBeforeJudge(eventEnum);
        m_EventTable[eventEnum] = (CallBack<T>)m_EventTable[eventEnum] - callBack;
        OnRemoveListenerLaterJudge(eventEnum);
    }

    public static void RemoveListener<T, X>(EventEnum eventEnum, CallBack<T, X> callBack) {
    
    
        OnRemoveListenerBeforeJudge(eventEnum);
        m_EventTable[eventEnum] = (CallBack<T, X>)m_EventTable[eventEnum] - callBack;
        OnRemoveListenerLaterJudge(eventEnum);
    }

    public static void RemoveListener<T, X, Y>(EventEnum eventEnum, CallBack<T, X, Y> callBack) {
    
    
        OnRemoveListenerBeforeJudge(eventEnum);
        m_EventTable[eventEnum] = (CallBack<T, X, Y>)m_EventTable[eventEnum] - callBack;
        OnRemoveListenerLaterJudge(eventEnum);
    }

    public static void RemoveListener<T, X, Y, Z>(EventEnum eventEnum, CallBack<T, X, Y, Z> callBack) {
    
    
        OnRemoveListenerBeforeJudge(eventEnum);
        m_EventTable[eventEnum] = (CallBack<T, X, Y, Z>)m_EventTable[eventEnum] - callBack;
        OnRemoveListenerLaterJudge(eventEnum);
    }

    public static void RemoveListener<T, X, Y, Z, W>(EventEnum eventEnum, CallBack<T, X, Y, Z, W> callBack) {
    
    
        OnRemoveListenerBeforeJudge(eventEnum);
        m_EventTable[eventEnum] = (CallBack<T, X, Y, Z, W>)m_EventTable[eventEnum] - callBack;
        OnRemoveListenerLaterJudge(eventEnum);
    }

    #endregion

    #region 广播事件
    public static void Broadcast(EventEnum eventEnum) {
    
    
        Delegate d;
        if (m_EventTable.TryGetValue(eventEnum, out d)) {
    
    
            CallBack callBack = d as CallBack;
            if (callBack != null) {
    
    
                callBack();
            }
        }
    }

    public static void Broadcast<T>(EventEnum eventEnum, T arg1) {
    
    
        Delegate d;
        if (m_EventTable.TryGetValue(eventEnum, out d)) {
    
    
            CallBack<T> callBack = d as CallBack<T>;
            if (callBack != null) {
    
    
                callBack(arg1);
            }
        }
    }

    public static void Broadcast<T, X>(EventEnum eventEnum, T arg1, X arg2) {
    
    
        Delegate d;
        if (m_EventTable.TryGetValue(eventEnum, out d)) {
    
    
            CallBack<T, X> callBack = d as CallBack<T, X>;
            if (callBack != null) {
    
    
                callBack(arg1, arg2);
            }
        }
    }

    public static void Broadcast<T, X, Y>(EventEnum eventEnum, T arg1, X arg2, Y arg3) {
    
    
        Delegate d;
        if (m_EventTable.TryGetValue(eventEnum, out d)) {
    
    
            CallBack<T, X, Y> callBack = d as CallBack<T, X, Y>;
            if (callBack != null) {
    
    
                callBack(arg1, arg2, arg3);
            }
        }
    }

    public static void Broadcast<T, X, Y, Z>(EventEnum eventEnum, T arg1, X arg2, Y arg3, Z arg4) {
    
    
        Delegate d;
        if (m_EventTable.TryGetValue(eventEnum, out d)) {
    
    
            CallBack<T, X, Y, Z> callBack = d as CallBack<T, X, Y, Z>;
            if (callBack != null) {
    
    
                callBack(arg1, arg2, arg3, arg4);
            }
        }
    }

    public static void Broadcast<T, X, Y, Z, W>(EventEnum eventEnum, T arg1, X arg2, Y arg3, Z arg4, W arg5) {
    
    
        Delegate d;
        if (m_EventTable.TryGetValue(eventEnum, 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);
            }
        }
    }

    #endregion
}

5. 测试

创建场景:
在这里插入图片描述
BtnClick:

/*
 * FileName:    BtnClick
 * Author:      ming
 * CreateTime:  2023/6/28 17:41:23
 * Description:
 * 
*/
using UnityEngine;
using System.Collections;
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;

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

    void Start()
    {
    
    
        noParameter.onClick.AddListener(() => {
    
    
            EventCenter.Broadcast(EventEnum.ShowText0);
        });
        oneParameter.onClick.AddListener(() => {
    
    
            EventCenter.Broadcast(EventEnum.ShowText1, "hello world!!!");
        });
        twoParameter.onClick.AddListener(() => {
    
    
            EventCenter.Broadcast(EventEnum.ShowText2, "hello world!!!", 2.0f);
        });
        threeParameter.onClick.AddListener(() =>
        {
    
    
            EventCenter.Broadcast(EventEnum.ShowText3, "hello world!!!", 2.0f, 3);
        });
        fourParameter.onClick.AddListener(() =>
        {
    
    
            EventCenter.Broadcast(EventEnum.ShowText4, "hello world!!!", 2.0f, 3, "ming");
        });
        fiveParameter.onClick.AddListener(() =>
        {
    
    
            EventCenter.Broadcast(EventEnum.ShowText5, "hello world!!!", 2.0f, 3, "ming", 5);
        });
    }
}

ShowText:

/*
 * FileName:    ShowText
 * Author:      ming
 * CreateTime:  2023/6/28 18:07:46
 * Description:
 * 
*/
using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class ShowText : MonoBehaviour
{
    
    
    void Awake() 
    {
    
    
        gameObject.SetActive(false);
        EventCenter.AddListener(EventEnum.ShowText0, ShowText0);
        EventCenter.AddListener<string>(EventEnum.ShowText1, ShowText1);
        EventCenter.AddListener<string, float>(EventEnum.ShowText2, ShowText2);
        EventCenter.AddListener<string, float, int>(EventEnum.ShowText3, ShowText3);
        EventCenter.AddListener<string, float, int, string>(EventEnum.ShowText4, ShowText4);
        EventCenter.AddListener<string, float, int, string, int>(EventEnum.ShowText5, ShowText5);
    }

    void OnDestroy()
    {
    
    
        EventCenter.RemoveListener(EventEnum.ShowText0, ShowText0);
        EventCenter.RemoveListener<string>(EventEnum.ShowText1, ShowText1);
        EventCenter.RemoveListener<string, float>(EventEnum.ShowText2, ShowText2);
        EventCenter.RemoveListener<string, float, int>(EventEnum.ShowText3, ShowText3);
        EventCenter.RemoveListener<string, float, int, string>(EventEnum.ShowText4, ShowText4);
        EventCenter.RemoveListener<string, float, int, string, int>(EventEnum.ShowText5, ShowText5);
    }

    void ShowText0() 
    {
    
    
        gameObject.SetActive(true);
        transform.GetComponent<Text>().text = "noParameter";
    }

    void ShowText1(string str) 
    {
    
    
        gameObject.SetActive(true);
        transform.GetComponent<Text>().text = str;
    }

    void ShowText2(string str, float a) 
    {
    
    
        gameObject.SetActive(true);
        transform.GetComponent<Text>().text = str + a;
    }

    public void ShowText3(string str, float a, int b)
    {
    
    
        gameObject.SetActive(true);
        GetComponent<Text>().text = str + a + b;
    }

    public void ShowText4(string str, float a, int b, string str2)
    {
    
    
        gameObject.SetActive(true);
        GetComponent<Text>().text = str + a + b + str2;
    }

    public void ShowText5(string str, float a, int b, string str2, int c)
    {
    
    
        gameObject.SetActive(true);
        GetComponent<Text>().text = str + a + b + str2 + c;
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_45136016/article/details/131432267