初学者,自用笔记

观察者模式-简单unity事件中心(基于UnityAction)

用例

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

public interface IEventInfo
{ };

public class EventInfo<T> : IEventInfo
{
    public UnityAction<T> actions;
    public EventInfo(UnityAction<T> action)
    {
        this.actions = action;
    }
}

public class EventInfo : IEventInfo
{
    public UnityAction actions;
    public EventInfo(UnityAction action)
    {
        this.actions = action;
    }
}

// 被观察者接口:定义被观察者必须实现的行为
public interface IObserver
{
    string EventName { get; } // 订阅的事件名称
    void Subscribe(); // 订阅事件
    void Unsubscribe(); // 取消订阅
    void OnEventTrigger(); // 无参事件响应
    void OnEventTrigger<T>(T param); // 带参事件响应
}

public class EventCenter : TheManager<EventCenter> 
{
    //存储所有事件
    private Dictionary<string,IEventInfo> allEvent = new Dictionary<string, IEventInfo>();

    //添加无参事件
    public void AddEventList(string _name,UnityAction _action)
    {
        if(allEvent.ContainsKey(_name))
        {
            //将新方法添加到已有事件的委托链中
            (allEvent[_name] as EventInfo).actions += _action;
        }
        else
        {
            // 不存在则创建新的事件信息对象并添加到字典
            allEvent.Add(_name, new EventInfo(_action));
        }

    }

    // 添加带参数的泛型事件
    public void AddEventList<T>(string _name, UnityAction<T> _action)
    {
        if (allEvent.ContainsKey(_name))
        {
            // 将新方法添加到已有泛型事件的委托链中
            (allEvent[_name] as EventInfo<T>).actions += _action;
        }
        else
        {
            // 不存在则创建新的泛型事件信息对象并添加到字典
            allEvent.Add(_name, new EventInfo<T>(_action));
        }
    }

    // 触发无参事件
    public void TriggerEvent(string _name)
    {
        // 检查事件是否存在
        if (allEvent.TryGetValue(_name, out IEventInfo eventInfo))
        {
            // 转换为无参事件类型并调用
            EventInfo info = eventInfo as EventInfo;
            if (info != null && info.actions != null)
            {
                info.actions.Invoke();
            }
        }
    }

    // 触发带参数的泛型事件
    public void TriggerEvent<T>(string _name, T _param)
    {
        // 检查事件是否存在
        if (allEvent.TryGetValue(_name, out IEventInfo eventInfo))
        {
            // 转换为对应泛型事件类型并调用
            EventInfo<T> info = eventInfo as EventInfo<T>;
            if (info != null && info.actions != null)
            {
                info.actions.Invoke(_param);
            }
        }
    }

    // 移除无参事件
    public void RemoveEvent(string _name, UnityAction _action)
    {
        if (allEvent.TryGetValue(_name, out IEventInfo eventInfo))
        {
            EventInfo info = eventInfo as EventInfo;
            if (info != null)
            {
                // 从委托链中移除指定方法
                info.actions -= _action;
            }
        }
    }

    // 移除带参数的泛型事件
    public void RemoveEvent<T>(string _name, UnityAction<T> _action)
    {
        if (allEvent.TryGetValue(_name, out IEventInfo eventInfo))
        {
            EventInfo<T> info = eventInfo as EventInfo<T>;
            if (info != null)
            {
                // 从委托链中移除指定方法
                info.actions -= _action;
            }
        }
    }

    // 清空所有事件
    public void ClearAllEvents()
    {
        allEvent.Clear();
        // 可选:重置单例(根据需求决定是否需要)
        // instance = null;
    }

    // 移除指定名称的事件
    public void RemoveEventByName(string _name)
    {
        if (allEvent.ContainsKey(_name))
        {
            allEvent.Remove(_name);
        }
    }

}

接口化组件观察者

public abstract class ObserverComponent : MonoBehaviour, IObserver
{
    // 子类指定事件名称
    public string EventName { get; }

    // 订阅事件(子类重写实现具体订阅逻辑)
    public virtual void Subscribe()
    {
        if (string.IsNullOrEmpty(EventName))
        {
            Debug.LogError($"{gameObject.name}:事件名为空,订阅失败!");
            return;
        }
    }

    // 取消订阅(子类重写实现具体取消逻辑)
    public virtual void Unsubscribe()
    {
        if (string.IsNullOrEmpty(EventName)) return;
    }

    // 无参事件响应逻辑(子类实现)
    public virtual void OnEventTrigger();

    // 带参事件响应逻辑(子类实现)
    public virtual void OnEventTrigger<T>(T param);

    // 组件激活时订阅
    protected virtual void OnEnable()
    {
        Subscribe();
    }

    // 组件禁用时取消订阅
    protected virtual void OnDisable()
    {
        Unsubscribe();
    }

    // 组件销毁时再次取消订阅
    protected virtual void OnDestroy()
    {
        Unsubscribe();
    }
}

观察者模式-简单unity事件中心(基于C#原生Action)

public interface IEventInfo { }

public class EventInfo<T> : IEventInfo
{
    public Action<T> actions;
    public EventInfo(Action<T> action)
    {
        this.actions = action;
    }
}

public class EventInfo : IEventInfo
{
    public Action actions;
    public EventInfo(Action action)
    {
        this.actions = action;
    }
}

public interface IObserver
{
    string EventName { get; } // 订阅的事件名称
    void Subscribe(); // 订阅事件
    void Unsubscribe(); // 取消订阅
    void OnEventTrigger(); // 无参事件响应
    void OnEventTrigger<T>(T param); // 带参事件响应
}

// 单例事件中心
public class EventCenter : TheManager<EventCenter>
{
    private Dictionary<string, IEventInfo> allEvent = new Dictionary<string, IEventInfo>();

    #region 无参事件操作
    // 添加无参事件订阅
    public void AddEventList(string eventName, Action action)
    {
        if (allEvent.ContainsKey(eventName))
        {
            (allEvent[eventName] as EventInfo).actions += action;
        }
        else
        {
            allEvent.Add(eventName, new EventInfo(action));
        }
    }

    // 触发无参事件
    public void TriggerEvent(string eventName)
    {
        if (allEvent.TryGetValue(eventName, out IEventInfo eventInfo))
        {
            EventInfo info = eventInfo as EventInfo;
            info?.actions?.Invoke();
        }
    }

    // 移除无参事件订阅
    public void RemoveEventList(string eventName, Action action)
    {
        if (allEvent.TryGetValue(eventName, out IEventInfo eventInfo))
        {
            EventInfo info = eventInfo as EventInfo;
            info?.actions -= action;
        }
    }
    #endregion

    #region 带参泛型事件操作
    // 添加带参事件订阅
    public void AddEventList<T>(string eventName, Action<T> action)
    {
        if (allEvent.ContainsKey(eventName))
        {
            (allEvent[eventName] as EventInfo<T>).actions += action;
        }
        else
        {
            allEvent.Add(eventName, new EventInfo<T>(action));
        }
    }

    // 触发带参事件
    public void TriggerEvent<T>(string eventName, T param)
    {
        if (allEvent.TryGetValue(eventName, out IEventInfo eventInfo))
        {
            EventInfo<T> info = eventInfo as EventInfo<T>;
            info?.actions?.Invoke(param);
        }
    }

    // 移除带参事件订阅
    public void RemoveEventList<T>(string eventName, Action<T> action)
    {
        if (allEvent.TryGetValue(eventName, out IEventInfo eventInfo))
        {
            EventInfo<T> info = eventInfo as EventInfo<T>;
            info?.actions -= action;
        }
    }
    #endregion

    // 清空所有事件
    public void ClearAllEvents() => allEvent.Clear();

    // 根据名称移除事件
    public void RemoveEventByName(string eventName)
    {
        if (allEvent.ContainsKey(eventName))
            allEvent.Remove(eventName);
    }
}

优化

// 事件消息基础接口:所有事件消息需实现此接口
public interface IEventMsg { }

// 事件总线:基于泛型的类型安全事件管理核心类
public static class EventCenter
{
    // 事件委托基础接口:定义清空委托的统一行为
    private interface IEvectInfo
    {
        void Clear();
    }

    // 泛型事件委托容器,禁止继承
    private sealed class EvectInfo<T> : IEvectInfo where T : IEventMsg
    {
        // 事件回调列表
        public Action<T> Actions;
        // 清空回调,避免内存泄漏
        public void Clear() => Actions = null;
    }

    // 订阅令牌
    public readonly struct SubscribeToken<T> where T : IEventMsg
    {
        private readonly Action<T> _listener; // 存储订阅的回调引用
        // 内部构造:仅EventCenter可创建
        internal SubscribeToken(Action<T> listener) => _listener = listener;

        // 取消订阅:调用EventCenter的移除方法
        public void Unsubscribe() => EventCenter.RemoveEventList<T>(_listener);
        // 令牌是否有效:判断回调引用是否存在
        public bool IsValid => _listener != null;
    }

    // 事件字典:按事件类型存储对应的委托容器
    private static readonly Dictionary<Type, IEvectInfo> _eventDict = new();

    // 获取指定事件类型的委托容器(不存在则创建)
    private static EvectInfo<T> GetEventInfo<T>() where T : IEventMsg
    {
        var type = typeof(T);
        // 尝试获取已有委托容器
        if (_eventDict.TryGetValue(type, out var d)) return (EvectInfo<T>)d;

        // 新建并存入字典
        var created = new EvectInfo<T>();
        _eventDict[type] = created;
        return created;
    }

    // 添加事件订阅
    public static SubscribeToken<T> AddEventList<T>(Action<T> listener) where T : IEventMsg
    {
        // 空校验:避免空回调导致异常
        if (listener == null) throw new ArgumentNullException(nameof(listener));
        // 添加回调到委托列表
        GetEventInfo<T>().Actions += listener;
        // 返回令牌
        return new SubscribeToken<T>(listener);
    }

    // 移除事件订阅
    public static void RemoveEventList<T>(Action<T> listener) where T : IEventMsg
    {
        // 空值直接返回:避免无效操作
        if (listener == null) return;

        var type = typeof(T);
        // 仅当存在该事件类型时执行移除
        if (_eventDict.TryGetValue(type, out var d))
        {
            var del = (EvectInfo<T>)d;
            del.Actions -= listener;
            // 无回调时移除字典项:减少内存占用
            if (del.Actions == null) _eventDict.Remove(type);
        }
    }

    // 触发事件(in关键字:引用传递,减少结构体拷贝开销)
    public static void TriggerEvent<T>(in T msg) where T : IEventMsg
    {

        GetEventInfo<T>().Actions?.Invoke(msg);
    }

    // 清空所有事件:释放委托引用,避免内存泄漏
    public static void ClearAllEvents()
    {
        // 先清空每个委托容器的回调
        Type[] keys = new Type[_eventDict.Count];
        //使用array复制数值,同时避免list的开销
        _eventDict.Keys.CopyTo(keys, 0);
        for (int i = 0; i < keys.Length; i++)
        {
            _eventDict[keys[i]].Clear();
        }        
        // 再清空字典
        _eventDict.Clear();
    }
}

vc框架依赖注入

public interface IEventMsg { }

public interface IEventCenter
{
    EventCenter.SubscribeToken<T> AddEventList<T>(Action<T> listener) where T : IEventMsg;
    void RemoveEventList<T>(Action<T> listener) where T : IEventMsg;
    void TriggerEvent<T>(in T msg) where T : IEventMsg;
    void ClearAllEvents();
}

// 非 static:由 DI 容器创建与管理(不是全局单例)
public sealed class EventCenter : IEventCenter
{
    private interface IEventInfo
    {
        void Clear();
    }

    private sealed class EventInfo<T> : IEventInfo where T : IEventMsg
    {
        public Action<T> actions;
        public void Clear() => actions = null;
    }

    // 订阅令牌:绑定到某个 EventCenter 实例
    public readonly struct SubscribeToken<T> where T : IEventMsg
    {
        private readonly EventCenter _owner;
        private readonly Action<T> _listener;

        internal SubscribeToken(EventCenter owner, Action<T> listener)
        {
            _owner = owner;
            _listener = listener;
        }

        public bool IsValid => _owner != null && _listener != null;

        public void Unsubscribe()
        {
            if (!IsValid) return;
            _owner.RemoveEventList<T>(_listener);
        }
    }

    private readonly Dictionary<Type, IEventInfo> _eventDict = new Dictionary<Type, IEventInfo>();

    private EventInfo<T> GetEventInfo<T>() where T : IEventMsg
    {
        var type = typeof(T);
        if (_eventDict.TryGetValue(type, out var info)) return (EventInfo<T>)info;

        var created = new EventInfo<T>();
        _eventDict[type] = created;
        return created;
    }

    public SubscribeToken<T> AddEventList<T>(Action<T> listener) where T : IEventMsg
    {
        if (listener == null) throw new ArgumentNullException(nameof(listener));
        GetEventInfo<T>().actions += listener;
        return new SubscribeToken<T>(this, listener);
    }

    public void RemoveEventList<T>(Action<T> listener) where T : IEventMsg
    {
        if (listener == null) return;

        var type = typeof(T);
        if (_eventDict.TryGetValue(type, out var info))
        {
            var e = (EventInfo<T>)info;
            e.actions -= listener;

            if (e.actions == null)
                _eventDict.Remove(type);
        }
    }

    public void TriggerEvent<T>(in T msg) where T : IEventMsg
    {
        GetEventInfo<T>().actions?.Invoke(msg);
    }

    public void ClearAllEvents()
    {
        var keys = new Type[_eventDict.Count];
        _eventDict.Keys.CopyTo(keys, 0);

        for (int i = 0; i < keys.Length; i++)
            _eventDict[keys[i]].Clear();

        _eventDict.Clear();
    }
}

// 挂到场景物体:作为 VContainer 的入口
public sealed class GameLifetimeScope : LifetimeScope
{
    protected override void Configure(IContainerBuilder builder)
    {
        builder.Register<IEventCenter, EventCenter>(Lifetime.Singleton);
        builder.Register<GoldSystem>(Lifetime.Singleton);
    }
}

// 具体例子
public readonly struct GoldChanged : IEventMsg
{
    public readonly int Current;
    public readonly int Delta;

    public GoldChanged(int current, int delta)
    {
        Current = current;
        Delta = delta;
    }
}

public sealed class GoldSystem
{
    private readonly IEventCenter _eventCenter;
    private int _gold;

    public GoldSystem(IEventCenter eventCenter)
    {
        _eventCenter = eventCenter;
    }

    public void AddGold(int delta)
    {
        _gold += delta;
        _eventCenter.TriggerEvent(new GoldChanged(_gold, delta));
    }
}

public sealed class GoldUI : MonoBehaviour
{
    private IEventCenter _eventCenter;
    private GoldSystem _goldSystem;
    private EventCenter.SubscribeToken<GoldChanged> _token;

    [Inject]
    public void Construct(IEventCenter eventCenter, GoldSystem goldSystem)
    {
        _eventCenter = eventCenter;
        _goldSystem = goldSystem;
    }

    private void OnEnable()
    {
        _token = _eventCenter.AddEventList<GoldChanged>(OnGoldChanged);
    }

    private void OnDisable()
    {
        if (_token.IsValid) _token.Unsubscribe();
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.G))
            _goldSystem.AddGold(10);
    }

    private void OnGoldChanged(GoldChanged msg)
    {
        Debug.Log($"[GoldUI] Gold={msg.Current} delta={msg.Delta}");
    }
}