Разделение Unity — мониторинг и трансляция событий

Сначала поймите концепцию, то есть, что такое связь между кодами, и зачем нужна развязка (уменьшите степень связи)

(1) Что такое связь (степень связи): степень связи между кодами относится к степени взаимозависимости между модулями кода, то есть модификация одного модуля повлияет на ситуацию с другими модулями. То есть, если имя класса кода использует большую часть содержимого другого блока кода, то можно сказать, что два блока кода имеют высокую степень связанности.

(2) Зачем нужна развязка: Сильно связанный код обычно трудно поддерживать и расширять, потому что каждое изменение модуля или класса означает изменение других модулей или классов, что создает дополнительные риски и рабочую нагрузку.

Простой пример в единстве: сценарий A, сценарий B и сценарий A хотят вызвать функцию в сценарии B. В это время (1) либо получить экземпляр B в A и вызвать его (2), либо сделать B в одноэлементный режим (аналогично методу (1)); только таким образом A может вызывать контент в B, но это приведет к более высокой степени связи между двумя сценариями, поэтому вы можете прослушивать события, а система вещания — для решить проблему сопряжения кода

Мониторинг и трансляция событий — это паттерн проектирования кода, всего скриптов всего три, сначала покажем эти три скрипта.

1. Класс EventDefine (содержимое внутри не имеет ничего общего со скриптом, который я скопировал прямо из собственного проекта)

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

2. Класс обратного вызова

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 не используют синглтон, и я чувствую, что получение метода класса B в классе A улучшит сцепление кода, поэтому это использование мониторинга и трансляции

Шаг 1. Сначала добавьте элемент перечисления в перечисление EventDefine как событие, например ShowB.

Шаг 2: Прослушайте событие в классе B, т. е. используйте

EventCenter.AddListener(EventDefine.ShowB, B);//B — это функция, определенная в классе B (предполагающая отсутствие параметров), этот шаг лучше всего реализовать в функции пробуждения

 EventCenter.RemoveListener(EventDefine.ShowB, Show);//Этот шаг лучше всего реализовать в функции жизненного цикла OnDestroy

После шага 2 мониторинг события завершен, и следующим шагом является трансляция

Шаг 3: Вызов функции A в классе A 

 EventCenter.Broadcast(EventDefine.ShowB);//Обратите внимание, что это функция без параметров

 Таким образом, два несвязанных класса могут вызываться друг к другу, уменьшая связанность кода.

Guess you like

Origin blog.csdn.net/qq_62947569/article/details/130544515