初学者,自用笔记
观察者模式-简单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}");
}
}

京公网安备 11010502036488号