unity通过全局事件对项目进行解耦

一个类要是想调用另一个类的方法,例如A想调用B的方法。
方式一:引用
最简单的方式是A持有一个B类的引用,即A拥有一个B的成员对象。
方式二:设计模式(中介者模式)
或者A和B同属于一个对象C,通过对象C调用对方(中介者模式),例如QQ群,A和B互相没有对方好友,但是都在一个QQ群C,他们可以在C互相和对方说话。
方式三:静态(通常是单例模式,B是管理类等)
将B中的方法设置为静态方法。
但是项目中,有N多类,A和B完全没有关系,不宜有对方的引用,并且都不是工具类,不宜设置为静态方法。那么此时,我们该如何让A和B建立联系呢?
答案是使用全局事件系统。
提取出来一个可以全局访问的事件列表(字典)

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,
}

索引是枚举,值是委托类型。
然后A、B将自身需要给外部调用的方法注册进去。
此处拿员工老板举例。
老板提供收钱的方法,员工负责调用。

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

实际效果演示如下:
在这里插入图片描述
总结:
全局事件中用到了泛型(调用的时候确定数据类型),父类可以接受所有子类(Delegate可以接收所有子类),重载(注册的方法可以有参数,也可以没有参数)三部分。
有点类似中介者模式,全局事件作为一个中介,向外提供一个事件注册和调用,达到了类与类之间解耦的问题。
Demo

猜你喜欢

转载自blog.csdn.net/qq_40629631/article/details/121545729