Unity解耦合--事件的监听和广播

首先明白一个概念,那就是代码之间的耦合性是什么,为什么需要解耦合(降低耦合度)

(1).什么是耦合性(耦合度):代码之间的耦合度代码模块之间相互依赖的程度,即一个模块的修改会影响到其他模块的情况。也就是说一个代码类名如果用到了大量另一个代码块的内容,那么就可以称之为这两个代码块之间具有高耦合度

(2).为什么需要解耦:高耦合的代码通常难以维护和扩展,因为每次对一个模块或类进行修改都意味着要涉及到其他模块或类的变更,这会带来额外的风险和工作量。

在unity中举个简单的例子就是,一个脚本A,一个脚本B,脚本A想要调用脚本B中的函数,这个时候(1)要么在A中获取到B的实例,进行调用(2)要么把B做成单例模式(和方法(1)类似);只有这样才能让A调用到B中的内容,但是就会导致这两个脚本的耦合度变高,因此就可以通过事件的监听和广播系统来解决代码耦合性的问题

事件的监听和广播就是一种代码的设计模式,总共就三个脚本,先把这三个脚本展示出来

1.EventDefine类(里面的内容与该脚本无关,这是我从我自己的项目里面直接copy出来的)

public enum EventDefine
{
    ShowGamePanel,
    DecidePath,
    AddScore,
    UpdateScoreText,
    PlayerMove,
    AddDiamond,
    UpadteDiamondText,
    ShowGameOverPanel,
    ShowShopPanel,
    ShowMainPanel,
    ChangeSkin,
    Hint,
    ShowResetPanel,
    ShowRankPanel,
    PlayeClickAudio,
    IsMusciOn,
}

2. CallBack类

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

3.EventCenter类

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EventCenter
{
    private static Dictionary<EventDefine, Delegate> m_EventTable = new Dictionary<EventDefine, Delegate>();

    private static void OnListenerAdding(EventDefine eventType, Delegate callBack)
    {
        if (!m_EventTable.ContainsKey(eventType))
        {
            m_EventTable.Add(eventType, null);
        }
        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()));
        }
    }
    private static void OnListenerRemoving(EventDefine 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));
        }
    }
    private static void OnListenerRemoved(EventDefine eventType)
    {
        if (m_EventTable[eventType] == null)
        {
            m_EventTable.Remove(eventType);
        }
    }
    //no parameters
    public static void AddListener(EventDefine eventType, CallBack callBack)
    {
        OnListenerAdding(eventType, callBack);
        m_EventTable[eventType] = (CallBack)m_EventTable[eventType] + callBack;
    }
    //Single parameters
    public static void AddListener<T>(EventDefine eventType, CallBack<T> callBack)
    {
        OnListenerAdding(eventType, callBack);
        m_EventTable[eventType] = (CallBack<T>)m_EventTable[eventType] + callBack;
    }
    //two parameters
    public static void AddListener<T, X>(EventDefine eventType, CallBack<T, X> callBack)
    {
        OnListenerAdding(eventType, callBack);
        m_EventTable[eventType] = (CallBack<T, X>)m_EventTable[eventType] + callBack;
    }
    //three parameters
    public static void AddListener<T, X, Y>(EventDefine eventType, CallBack<T, X, Y> callBack)
    {
        OnListenerAdding(eventType, callBack);
        m_EventTable[eventType] = (CallBack<T, X, Y>)m_EventTable[eventType] + callBack;
    }
    //four parameters
    public static void AddListener<T, X, Y, Z>(EventDefine eventType, CallBack<T, X, Y, Z> callBack)
    {
        OnListenerAdding(eventType, callBack);
        m_EventTable[eventType] = (CallBack<T, X, Y, Z>)m_EventTable[eventType] + callBack;
    }
    //five parameters
    public static void AddListener<T, X, Y, Z, W>(EventDefine eventType, CallBack<T, X, Y, Z, W> callBack)
    {
        OnListenerAdding(eventType, callBack);
        m_EventTable[eventType] = (CallBack<T, X, Y, Z, W>)m_EventTable[eventType] + callBack;
    }

    //no parameters
    public static void RemoveListener(EventDefine eventType, CallBack callBack)
    {
        OnListenerRemoving(eventType, callBack);
        m_EventTable[eventType] = (CallBack)m_EventTable[eventType] - callBack;
        OnListenerRemoved(eventType);
    }
    //single parameters
    public static void RemoveListener<T>(EventDefine eventType, CallBack<T> callBack)
    {
        OnListenerRemoving(eventType, callBack);
        m_EventTable[eventType] = (CallBack<T>)m_EventTable[eventType] - callBack;
        OnListenerRemoved(eventType);
    }
    //two parameters
    public static void RemoveListener<T, X>(EventDefine eventType, CallBack<T, X> callBack)
    {
        OnListenerRemoving(eventType, callBack);
        m_EventTable[eventType] = (CallBack<T, X>)m_EventTable[eventType] - callBack;
        OnListenerRemoved(eventType);
    }
    //three parameters
    public static void RemoveListener<T, X, Y>(EventDefine eventType, CallBack<T, X, Y> callBack)
    {
        OnListenerRemoving(eventType, callBack);
        m_EventTable[eventType] = (CallBack<T, X, Y>)m_EventTable[eventType] - callBack;
        OnListenerRemoved(eventType);
    }
    //four parameters
    public static void RemoveListener<T, X, Y, Z>(EventDefine eventType, CallBack<T, X, Y, Z> callBack)
    {
        OnListenerRemoving(eventType, callBack);
        m_EventTable[eventType] = (CallBack<T, X, Y, Z>)m_EventTable[eventType] - callBack;
        OnListenerRemoved(eventType);
    }
    //five parameters
    public static void RemoveListener<T, X, Y, Z, W>(EventDefine 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);
    }


    //no parameters
    public static void Broadcast(EventDefine 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));
            }
        }
    }
    //single parameters
    public static void Broadcast<T>(EventDefine 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));
            }
        }
    }
    //two parameters
    public static void Broadcast<T, X>(EventDefine 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));
            }
        }
    }
    //three parameters
    public static void Broadcast<T, X, Y>(EventDefine 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));
            }
        }
    }
    //four parameters
    public static void Broadcast<T, X, Y, Z>(EventDefine 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));
            }
        }
    }
    //five parameters
    public static void Broadcast<T, X, Y, Z, W>(EventDefine 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. EventDefine类,这个类是枚举类型,可以理解为里面存放的是事件的名称

2.CallBack类,这个类里面存放的全是不同参数的委托类型

这两个脚本的都是为第三个脚本做准备的

3.EventCenter类,首先,这个类的内部是一个字典的集合,字典的键为EventDefine的枚举,字典的键对应的值为就为CallBack类型的委托(可以理解为将它们绑定在一起)

以下方法都要注意参数个数的重载(下面是无参方法的举例)

其中AddListener(EventDefine eventType, CallBack callBack)方法就是为添加监听事件,也就是将EventDefine的枚举和CallBack类型的委托对应的添加进字典中

RemoveListener(EventDefine eventType, CallBack callBack)方法顾名思义就算将CallBack类型的委托在字典中移除

Broadcast(EventDefine eventType)方法是用来广播的,我的理解解释调用EventDefine eventType绑定的函数

解释完上面如此抽象的类的概念后,现在我们来实际使用一下

现在假设一个场景,类A中有一个函数A需要调用类B中的函数B(假设类A和类B已经挂载在游戏对象上了),由于类A和类B都没有使用单例,又觉得在类A中获取类B的方法会提高代码的耦合性,因此这是就可以使用监听与广播

步骤1:先在EventDefine枚举中添加一个枚举项当作事件,比如ShowB

步骤2:在类B中监听事件,也就是使用

EventCenter.AddListener(EventDefine.ShowB, B);//B是类B中定义的一个函数(假设无参),这一步最好在awake函数中实现

 EventCenter.RemoveListener(EventDefine.ShowB, Show);//这一步最好在OnDestroy生命周期函数中实现

在进行完步骤2后事件的监听就完成了,接下来就是广播

步骤3:在类A中的函数A中调用 

 EventCenter.Broadcast(EventDefine.ShowB);//注意这里是无参函数

 这样就可以将两个无关联的类进行相互调用,降低了代码的耦合度

猜你喜欢

转载自blog.csdn.net/qq_62947569/article/details/130544515