Unity decouples the project through global events

If a class wants to call a method of another class, for example, A wants to call a method of B.
Way 1: Reference
The simplest way is that A holds a reference to class B, that is, A owns a member object of B.
Method 2: Design mode (intermediary mode)
or A and B belong to the same object C, call each other through object C (intermediary mode), such as QQ group, A and B do not have each other's friends, but both are in the same QQ group C , they can talk to each other at C.
Method 3: Static (usually singleton mode, B is a management class, etc.)
Set the method in B as a static method.
However, in the project, there are more than N categories, A and B are completely irrelevant, and it is not appropriate to have references to each other, and they are not tool classes, so they should not be set as static methods. So at this time, how do we make A and B establish a connection?
The answer is to use the global event system.
Extract a list of events that can be accessed globally (dictionary)

public class EventManager : MonoBehaviour
{
    
    

    public static Dictionary<EventType, List<Delegate>> EventDic = new Dictionary<EventType, List<Delegate>>();

    public delegate void CallBack();
    public delegate void CallBack<T>(T parameter);

    public static void AddListener(EventType eventType, CallBack callBack)
    {
    
    
        if (EventDic.ContainsKey(eventType))
        {
    
    
            EventDic[eventType].Add(callBack);
        }
        else
        {
    
    
            EventDic.Add(eventType, new List<Delegate>() {
    
     callBack });
        }
    }

    public static void RemoveListener(EventType eventType, CallBack callBack)
    {
    
    
        if (EventDic.ContainsKey(eventType))
        {
    
    
            CallBack currentCallBack = null;
            foreach (var item in EventDic[eventType])
            {
    
    
                currentCallBack = item as CallBack;
                if (currentCallBack == callBack)
                {
    
    
                    currentCallBack = callBack;
                }
            }
            if (currentCallBack != null)
            {
    
    
                EventDic[eventType].Remove(callBack);
            }
            if (EventDic[eventType].Count == 0)
            {
    
    
                EventDic.Remove(eventType);
            }
        }
        else
        {
    
    
            throw new Exception("当前系统未注册该事件");
        }
    }

    public static void AddListener<T>(EventType eventType, CallBack<T> callBack)
    {
    
    
        if (EventDic.ContainsKey(eventType))
        {
    
    
            EventDic[eventType].Add(callBack);
        }
        else
        {
    
    
            EventDic.Add(eventType, new List<Delegate>() {
    
     callBack });
        }
    }

    public static void RemoveListener<T>(EventType eventType, CallBack<T> callBack)
    {
    
    
        if (EventDic.ContainsKey(eventType))
        {
    
    
            CallBack<T> currentCallBack = null;
            foreach (var item in EventDic[eventType])
            {
    
    
                currentCallBack = item as CallBack<T>;
                if (currentCallBack == callBack)
                {
    
    
                    currentCallBack = callBack;
                }
            }
            if (currentCallBack != null)
            {
    
    
                EventDic[eventType].Remove(callBack);
            }
            if (EventDic[eventType].Count == 0)
            {
    
    
                EventDic.Remove(eventType);
            }
        }
        else
        {
    
    
            throw new Exception("当前系统未注册该事件");
        }
    }



    public static void Dispatch(EventType eventType)
    {
    
    
        if (EventDic.ContainsKey(eventType))
        {
    
    
            CallBack callBack;
            foreach (var item in EventDic[eventType])
            {
    
    
                callBack = item as CallBack;
                if (callBack != null)
                {
    
    
                    callBack();
                }
            }
        }
        else
        {
    
    
            throw new Exception("当前事件系统不包含该事件");
        }
    }

    public static void Dispatch<T>(EventType eventType, T parameter)
    {
    
    
        if (EventDic.ContainsKey(eventType))
        {
    
    
            CallBack<T> callBack;
            foreach (var item in EventDic[eventType])
            {
    
    
                callBack = item as CallBack<T>;
                if (callBack != null)
                {
    
    
                    callBack(parameter);
                }
            }
        }
        else
        {
    
    
            throw new Exception("当前事件系统不包含该事件");
        }
    }

}

public class EventData 
{
    
    
    public int money;
}

public enum EventType
{
    
    
    AddMoney,
    AddMoneyWithParameter,
    AddMoneyWithEventData,
}

The index is an enum and the value is a delegate type.
Then A and B register the methods they need to call externally.
Here is an example of an employee boss.
The boss provides a method of collecting money, and the employee is responsible for calling it.

public class Boss: MonoBehaviour
{
    
    
    public Button AddListenerButton;
    public Button RemoveListenerButton;

    void Awake()
    {
    
    
        AddListenerButton.onClick.AddListener(() =>
        {
    
    
            EventManager.AddListener(EventType.AddMoney, GetMoney);
            EventManager.AddListener<int>(EventType.AddMoneyWithParameter, GetMoneyWihtPrameter);
            EventManager.AddListener<EventData>(EventType.AddMoneyWithEventData, GetmoneyWithEventData);
        });

        RemoveListenerButton.onClick.AddListener(() =>
        {
    
    
            EventManager.RemoveListener(EventType.AddMoney, GetMoney);
            EventManager.RemoveListener<int>(EventType.AddMoneyWithParameter, GetMoneyWihtPrameter);
            EventManager.RemoveListener<EventData>(EventType.AddMoneyWithEventData, GetmoneyWithEventData);
        });
    }
    void GetMoney()
    {
    
    
        Debug.Log("收到用户购买的资金,员工真棒");
    }
    void GetMoneyWihtPrameter(int money)
    {
    
    
        Debug.Log("收到用户购买的资金,员工真棒,收入赚了  " + money);
    }

    void GetmoneyWithEventData(EventData data) 
    {
    
    
        Debug.Log("通过事件数据收到用户购买的资金,员工真棒,收入赚了  " + data.money);
    }
}

public class Staff : MonoBehaviour
{
    
    
    public Button BuyButton;

    public Button BuyButtonWithParameter;

    public Button BuyButtonWithEventData;

    private void Start()
    {
    
    
        BuyButton.onClick.AddListener(() =>
        {
    
    
            EventManager.Dispatch(EventType.AddMoney);
        });
        BuyButtonWithParameter.onClick.AddListener(() =>
        {
    
    
            EventManager.Dispatch(EventType.AddMoneyWithParameter, 100);
        });
        BuyButtonWithEventData.onClick.AddListener(() =>
        {
    
    
            EventManager.Dispatch(EventType.AddMoneyWithEventData, new EventData() {
    
     money = 200});
        });
    }
}

The actual effect is demonstrated as follows:
insert image description here
Summary:
Generics are used in global events (the data type is determined when calling), the parent class can accept all subclasses (Delegate can receive all subclasses), overloading (registered methods can have parameters, and Can have no parameters) three parts.
Somewhat similar to the intermediary mode, the global event acts as an intermediary to provide an event registration and call to the outside world, achieving the problem of decoupling between classes.
demo

Guess you like

Origin blog.csdn.net/qq_40629631/article/details/121545729