Desacoplamento do Unity - monitoramento e transmissão de eventos

Primeiro entenda um conceito, ou seja, qual é o acoplamento entre os códigos, e por que o desacoplamento é necessário (diminuir o grau de acoplamento)

(1) O que é acoplamento (grau de acoplamento): o grau de acoplamento entre códigos refere-se ao grau de interdependência entre módulos de código, ou seja, a modificação de um módulo afetará a situação de outros módulos. Ou seja, se um nome de classe de código usa muito conteúdo de outro bloco de código, pode-se dizer que os dois blocos de código têm um alto grau de acoplamento

(2) Por que o desacoplamento é necessário: código altamente acoplado geralmente é difícil de manter e expandir, porque cada modificação em um módulo ou classe significa mudanças em outros módulos ou classes, o que traz riscos e carga de trabalho adicionais.

Um exemplo simples na unidade é um script A, um script B e o script A deseja chamar a função no script B. Neste momento (1), obtenha a instância de B em A e chame-a (2) ou faça B em um modo singleton (semelhante ao método (1)); somente desta forma A pode chamar o conteúdo em B, mas levará a um maior grau de acoplamento entre os dois scripts, para que você possa ouvir eventos e o sistema Broadcast para resolver o problema de acoplamento de código

O monitoramento e a transmissão de eventos são um padrão de design de código. Existem apenas três scripts no total. Vamos mostrar esses três scripts primeiro.

1. Classe EventDefine (o conteúdo dentro dela não tem nada a ver com o script, que copiei diretamente do meu próprio projeto)

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

2. Classe 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. Classe 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));
            }
        }
    }
}

Agora, para explicar o que cada script faz,

1. Classe EventDefine, esta classe é um tipo de enumeração, que pode ser entendida como o armazenamento do nome do evento

2. Classe CallBack, que armazena todos os tipos de delegados com diferentes parâmetros

Esses dois scripts estão em preparação para o terceiro script

3. classe EventCenter, em primeiro lugar, o interior desta classe é uma coleção de dicionários, as chaves do dicionário são a enumeração de EventDefine, e o valor correspondente à chave do dicionário é o delegado do tipo CallBack (que pode ser entendido como unindo-os)

Os métodos a seguir devem prestar atenção à sobrecarga do número de parâmetros (o seguinte é um exemplo de método sem parâmetros)

Entre eles, o método AddListener(EventDefine eventType, CallBack callBack) é adicionar eventos de escuta, ou seja, adicionar a enumeração de EventDefine e a enumeração do tipo CallBack no dicionário correspondentemente

O método RemoveListener(EventDefine eventType, CallBack callBack), como o nome indica, remove o delegado do tipo CallBack do dicionário

O método Broadcast(EventDefine eventType) é usado para transmissão. Meu entendimento é chamar a função vinculada por EventDefine eventType

Depois de explicar o conceito de tal classe abstrata acima, agora vamos realmente usá-la

Agora suponha um cenário, existe uma função A na classe A que precisa chamar a função B na classe B (supondo que a classe A e a classe B tenham sido montadas no objeto do jogo), pois nem a classe A nem a classe B usam um singleton, e sinto que obter o método da classe B na classe A melhorará o acoplamento do código, então esse é o uso de monitoramento e transmissão

Etapa 1: primeiro adicione um item de enumeração na enumeração EventDefine como um evento, como ShowB

Passo 2: Ouça o evento na classe B, ou seja, use

EventCenter.AddListener(EventDefine.ShowB, B);//B é uma função definida na classe B (sem parâmetros), esta etapa é melhor implementada na função de despertar

 EventCenter.RemoveListener(EventDefine.ShowB, Show);//Esta etapa é melhor implementada na função de ciclo de vida OnDestroy

Após a etapa 2, o monitoramento do evento é concluído, e a próxima etapa é a transmissão

Etapa 3: chamar a função A na classe A 

 EventCenter.Broadcast(EventDefine.ShowB);//Observe que esta é uma função sem parâmetros

 Dessa forma, duas classes não relacionadas podem ser chamadas entre si, reduzindo o acoplamento do código

Acho que você gosta

Origin blog.csdn.net/qq_62947569/article/details/130544515
Recomendado
Clasificación