// File : CECObserver.cs // Creator : Xu Wenbin // Date : 2014/4/10 // Converted to C#: 2024 using System; using System.Collections.Generic; using System.Linq; using UnityEngine; namespace BrewMonster { // class CECObservableChange // 封装 CECObservable 的变化通知数据 / Encapsulates change notification data for CECObservable public class CECObservableChange : IDisposable { public virtual void Dispose() { // Cleanup logic here } } // class CECObserver // 观察者基类:观察的 Model / Observer base class: observes Model public class CECObserver { public virtual void OnRegistered(Model model) { } public virtual void OnModelChange(Model model, CECObservableChange change) { } public virtual void OnUnregister(Model model) { } } // class CECObservable // 可观察者基类:被观察的 Model / Observable base class: the Model being observed // 提供观察者注册及通知功能 / Provides observer registration and notification functionality public class CECObservable where Model : class { private struct ObserverImpl { public CECObserver observer; // 观察者指针 / Observer pointer public int observeTimes; // 观察次数:为正数时,收到指定次数的 OnModelChange 消息后自动取消注册,为负数时为永久,为0值时无效 / Observe times: when positive, auto-unregister after receiving specified OnModelChange messages; when negative, permanent; when 0, invalid public bool autoDeleteOnUnregister; // 取消注册时是否自动 delete / Whether to auto-delete on unregister public ObserverImpl(CECObserver observer, int observeTimes, bool autoDeleteOnUnregister) { this.observer = observer; this.observeTimes = observeTimes; this.autoDeleteOnUnregister = autoDeleteOnUnregister; if (this.observeTimes == 0) { Debug.Assert(false, "Observer times cannot be 0"); this.observeTimes = 1; // 默认观察次数为1 / Default observe times to 1 } } public bool Equals(ObserverImpl rhs) { return this.observer == rhs.observer; } public bool Equals(CECObserver pObserver) { return this.observer == pObserver; } public bool WillNotObserve() { // 是否不再观察目标 / Whether no longer observing target return observeTimes == 0; } public bool ObserveOnce() { // 收到一次观察消息时调用,返回是否不再观察 / Called when receiving one observe message, returns whether no longer observing if (observeTimes > 0) { --observeTimes; } return WillNotObserve(); } } private List m_observers = new List(); protected Model AsModel() { return this as Model; } public bool IsObserverRegistered(CECObserver pObserver) { return m_observers.Any(impl => impl.Equals(pObserver)); } public bool RegisterObserver(CECObserver pObserver, int observeTimes = -1, bool autoDeleteOnUnregister = false) { bool bRegistered = false; if (!IsObserverRegistered(pObserver)) { m_observers.Add(new ObserverImpl(pObserver, observeTimes, autoDeleteOnUnregister)); pObserver.OnRegistered(AsModel()); bRegistered = true; } return bRegistered; } public bool UnregisterObserver(CECObserver pObserver) { int index = m_observers.FindIndex(impl => impl.Equals(pObserver)); if (index >= 0) { return UnregisterObserverImpl(index); } return false; } public void NotifyObservers(CECObservableChange pChange) { Model pModel = AsModel(); for (int i = m_observers.Count - 1; i >= 0; i--) { ObserverImpl observerImpl = m_observers[i]; observerImpl.observer.OnModelChange(pModel, pChange); if (observerImpl.ObserveOnce()) { UnregisterObserverImpl(i); } } } private bool UnregisterObserverImpl(int index) { bool bUnRegistered = false; if (index >= 0 && index < m_observers.Count) { ObserverImpl observerImpl = m_observers[index]; observerImpl.observer.OnUnregister(AsModel()); if (observerImpl.autoDeleteOnUnregister) { // In C#, we don't manually delete objects, but we can set to null // The GC will handle cleanup } m_observers.RemoveAt(index); bUnRegistered = true; } return bUnRegistered; } } }