Unity解耦合-事件的监听与广播系统

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

Unity解耦合-事件的监听与广播系统

目的

解决代码之间耦合性问题

解决方法

利用委托封装事件方法,然后利用广播和监听事件来实现解耦。
优点:解决代码和代码之间的耦合性,每个脚本只需要关心自己要干的事情,不需要和外界进行联系。
缺点:添加监听时泛型的类型问题,必须明确参数的顺序,不可以出错,如果出错回报错。

  1. 委托脚本
    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);
  1. 事件处理中心类
    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. 事件码枚举类
    分别对应无参数、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
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值