150 lines
5.3 KiB
C#
150 lines
5.3 KiB
C#
// 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<Model>
|
|
{
|
|
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<Model> where Model : class
|
|
{
|
|
private struct ObserverImpl
|
|
{
|
|
public CECObserver<Model> 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<Model> 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<Model> 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<ObserverImpl> m_observers = new List<ObserverImpl>();
|
|
|
|
protected Model AsModel()
|
|
{
|
|
return this as Model;
|
|
}
|
|
|
|
public bool IsObserverRegistered(CECObserver<Model> pObserver)
|
|
{
|
|
return m_observers.Any(impl => impl.Equals(pObserver));
|
|
}
|
|
|
|
public bool RegisterObserver(CECObserver<Model> 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<Model> 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;
|
|
}
|
|
}
|
|
}
|